]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 2 Sep 2010 17:30:07 +0000 (13:30 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 2 Sep 2010 17:30:07 +0000 (13:30 -0400)
124 files changed:
Documentation/DocBook/80211.tmpl
MAINTAINERS
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/debug.h
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000-hw.h
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
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-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/Kconfig
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.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/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_acx.h
drivers/net/wireless/wl12xx/wl1251_boot.c
drivers/net/wireless/wl12xx/wl1251_boot.h
drivers/net/wireless/wl12xx/wl1251_cmd.h
drivers/net/wireless/wl12xx/wl1251_debugfs.c
drivers/net/wireless/wl12xx/wl1251_debugfs.h
drivers/net/wireless/wl12xx/wl1251_event.c
drivers/net/wireless/wl12xx/wl1251_event.h
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_init.h
drivers/net/wireless/wl12xx/wl1251_io.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_ps.h
drivers/net/wireless/wl12xx/wl1251_reg.h
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_rx.h
drivers/net/wireless/wl12xx/wl1251_sdio.c
drivers/net/wireless/wl12xx/wl1251_spi.c
drivers/net/wireless/wl12xx/wl1251_spi.h
drivers/net/wireless/wl12xx/wl1251_tx.c
drivers/net/wireless/wl12xx/wl1251_tx.h
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_scan.c
include/linux/nl80211.h
include/linux/spi/wl12xx.h
include/net/cfg80211.h
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
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/offchannel.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/nl80211.c
net/wireless/util.c
net/wireless/wext-core.c
net/wireless/wext-sme.c

index b84c9282828fd4bbcb8fa408398b483982a856c1..19a1210c2530681762b6d77b46901fa3374b54ec 100644 (file)
@@ -65,7 +65,6 @@
     </abstract>
   </setinfo>
   <book id="cfg80211-developers-guide">
-!Ainclude/net/cfg80211.h
     <bookinfo>
       <title>The cfg80211 subsystem</title>
 
index 93198c1980a949c22780454eaabc9abad5a1f013..7a49a7b5af1dcb8072692e1f55902b77d2161c8b 100644 (file)
@@ -4304,13 +4304,12 @@ F:      Documentation/filesystems/dlmfs.txt
 F:     fs/ocfs2/
 
 ORINOCO DRIVER
-M:     Pavel Roskin <proski@gnu.org>
-M:     David Gibson <hermes@gibson.dropbear.id.au>
 L:     linux-wireless@vger.kernel.org
 L:     orinoco-users@lists.sourceforge.net
 L:     orinoco-devel@lists.sourceforge.net
+W:     http://linuxwireless.org/en/users/Drivers/orinoco
 W:     http://www.nongnu.org/orinoco/
-S:     Maintained
+S:     Orphan
 F:     drivers/net/wireless/orinoco/
 
 OSD LIBRARY and FILESYSTEM
@@ -6376,7 +6375,7 @@ S:        Maintained
 F:     drivers/input/misc/wistron_btns.c
 
 WL1251 WIRELESS DRIVER
-M:     Kalle Valo <kalle.valo@iki.fi>
+M:     Kalle Valo <kvalo@adurom.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
@@ -6391,6 +6390,7 @@ W:        http://wireless.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
 F:     drivers/net/wireless/wl12xx/wl1271*
+F:     include/linux/spi/wl12xx.h
 
 WL3501 WIRELESS PCMCIA CARD DRIVER
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
index d32f2828b098ee63241e3b1e83c82d96ab2944df..a706202fa67c9360f70e3fc6ec2351b8f68e943f 100644 (file)
@@ -119,6 +119,7 @@ struct ath_common {
 
        u32 keymax;
        DECLARE_BITMAP(keymap, ATH_KEYMAX);
+       DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
        u8 splitmic;
 
        struct ath_regulatory regulatory;
index f2fceb10c9fcdd11f370f5b907e958420fbc708e..45789c8990d3e705fe890d4952edd903b5054de4 100644 (file)
@@ -700,10 +700,10 @@ ath5k_pci_probe(struct pci_dev *pdev,
        return 0;
 err_ah:
        ath5k_hw_detach(sc->ah);
-err_irq:
-       free_irq(pdev->irq, sc);
 err_free_ah:
        kfree(sc->ah);
+err_irq:
+       free_irq(pdev->irq, sc);
 err_free:
        ieee80211_free_hw(hw);
 err_map:
index 4cccc29964f6ddd0c7665369b034651d099a90cc..1b7c6d7fde93c1e7ca76520c503c5272247a1bd9 100644 (file)
@@ -312,6 +312,7 @@ static const struct {
        { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
        { ATH5K_DEBUG_DUMPBANDS, "dumpbands",   "dump bands" },
        { ATH5K_DEBUG_ANI,      "ani",          "adaptive noise immunity" },
+       { ATH5K_DEBUG_DESC,     "desc",         "descriptor chains" },
        { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
 };
 
@@ -955,7 +956,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
        struct ath5k_rx_status rs = {};
        int status;
 
-       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
                return;
 
        printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
@@ -997,7 +998,7 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
        struct ath5k_tx_status ts = {};
        int done;
 
-       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
                return;
 
        done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts);
index 606ae94a9157806b736f3c9d890c36a2f1edb762..9b22722a95f04a420da49ff22395d3629cc965ca 100644 (file)
@@ -95,6 +95,7 @@ struct ath5k_dbg_info {
  * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
  * @ATH5K_DEBUG_DUMPBANDS: dump bands
  * @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_DESC: descriptor setup
  * @ATH5K_DEBUG_ANY: show at any debug level
  *
  * The debug level is used to control the amount and type of debugging output
@@ -117,6 +118,7 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_DUMP_TX     = 0x00000200,
        ATH5K_DEBUG_DUMPBANDS   = 0x00000400,
        ATH5K_DEBUG_ANI         = 0x00002000,
+       ATH5K_DEBUG_DESC        = 0x00004000,
        ATH5K_DEBUG_ANY         = 0xffffffff
 };
 
index 3fef5931ec3a30dd901b928301f575d693b74758..bb2e21553d1be4d7b8e3cf47c1f86166951e2dc4 100644 (file)
@@ -137,11 +137,11 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
  * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
  *
  * @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmition rate
+ * @high: Flag to determine if we want to use high transmission rate
  * for ACKs or not
  *
  * If high flag is set, we tell hw to use a set of control rates based on
- * the current transmition rate (check out control_rates array inside reset.c).
+ * the current transmission rate (check out control_rates array inside reset.c).
  * If not hw just uses the lowest rate available for the current modulation
  * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
  */
index c7c44659237485bd4bac49d804e00d33a5596e9f..984ba92c7df3781fef83719fb8f07431e36ea9be 100644 (file)
@@ -1582,7 +1582,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
                        else if (curr_sym_off >= 31 && curr_sym_off <= 46)
                                mag_mask[2] |=
                                        plt_mag_map << (curr_sym_off - 31) * 2;
-                       else if (curr_sym_off >= 46 && curr_sym_off <= 53)
+                       else if (curr_sym_off >= 47 && curr_sym_off <= 53)
                                mag_mask[3] |=
                                        plt_mag_map << (curr_sym_off - 47) * 2;
 
@@ -2987,7 +2987,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
 
 
 /*
- * Set transmition power
+ * Set transmission power
  */
 int
 ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
index 4154959125b6fe1b3d435c30c703ae6fc30cd034..58912cd762d9808c199f78fbdb6ab97f5261e03f 100644 (file)
@@ -326,7 +326,7 @@ commit:
  * register). After this MAC and Baseband are
  * disabled and a full reset is needed to come
  * back. This way we save as much power as possible
- * without puting the card on full sleep.
+ * without putting the card on full sleep.
  */
 int ath5k_hw_on_hold(struct ath5k_hw *ah)
 {
@@ -344,7 +344,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
        /*
         * Put chipset on warm reset...
         *
-        * Note: puting PCI core on warm reset on PCI-E cards
+        * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
@@ -400,7 +400,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
        /*
         * Put chipset on warm reset...
         *
-        * Note: puting PCI core on warm reset on PCI-E cards
+        * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
index 31cfe468e3fc5fd8e1d85232207615056a8d3cba..2dab64bb23a8dc4aebb51d0d9f406e222059c670 100644 (file)
@@ -372,9 +372,13 @@ int ath9k_cmn_key_config(struct ath_common *common,
        set_bit(idx, common->keymap);
        if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                set_bit(idx + 64, common->keymap);
+               set_bit(idx, common->tkip_keymap);
+               set_bit(idx + 64, common->tkip_keymap);
                if (common->splitmic) {
                        set_bit(idx + 32, common->keymap);
                        set_bit(idx + 64 + 32, common->keymap);
+                       set_bit(idx + 32, common->tkip_keymap);
+                       set_bit(idx + 64 + 32, common->tkip_keymap);
                }
        }
 
@@ -399,10 +403,17 @@ void ath9k_cmn_key_delete(struct ath_common *common,
                return;
 
        clear_bit(key->hw_key_idx + 64, common->keymap);
+
+       clear_bit(key->hw_key_idx, common->tkip_keymap);
+       clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
+
        if (common->splitmic) {
                ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
                clear_bit(key->hw_key_idx + 32, common->keymap);
                clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+
+               clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
+               clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
        }
 }
 EXPORT_SYMBOL(ath9k_cmn_key_delete);
index 5e318cb662c665deda93364e3eebc37c00c39fad..f4672073ac0a3e37db701c6b99d37c5f6a5181d1 100644 (file)
@@ -1239,7 +1239,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
        /* Cancel all the running timers/work .. */
        cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_ani_work);
        cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
        ath9k_led_stop_brightness(priv);
 
@@ -1787,7 +1786,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
        priv->op_flags |= OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
        cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+       if (priv->op_flags & OP_ASSOCIATED)
+               cancel_delayed_work_sync(&priv->ath9k_ani_work);
        mutex_unlock(&priv->mutex);
 }
 
@@ -1801,9 +1801,10 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
        priv->op_flags &= ~OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
        priv->op_flags |= OP_FULL_RESET;
-       if (priv->op_flags & OP_ASSOCIATED)
+       if (priv->op_flags & OP_ASSOCIATED) {
                ath9k_htc_beacon_config(priv, priv->vif);
-       ath_start_ani(priv);
+               ath_start_ani(priv);
+       }
        ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
 }
index 243c1775f343f0b3400b0675708ee292bcb54e74..3dbff8d077667a224660464eddfcc2c1e008ea61 100644 (file)
@@ -33,7 +33,7 @@ int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
 
-int led_blink = 1;
+int led_blink;
 module_param_named(blink, led_blink, int, 0444);
 MODULE_PARM_DESC(blink, "Enable LED blink on activity");
 
index e955bb9d98cbe0380ef5d070005b373c1a132b8d..0b7d1253f0c0de6fbddb6eeba3b0c23af7831b08 100644 (file)
@@ -711,7 +711,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                        rs->rs_phyerr = phyerr;
                } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
-               else if (ads.ds_rxstatus8 & AR_MichaelErr)
+               else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
+                        rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
                        rs->rs_status |= ATH9K_RXERR_MIC;
        }
 
index a3fc987ebab003bd5fda0545fa581863b71ba806..534a91bcc1d980a28d26ae3ebdef57e2c99566ca 100644 (file)
@@ -870,15 +870,18 @@ static bool ath9k_rx_accept(struct ath_common *common,
                if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
                        *decrypt_error = true;
                } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
-                       if (ieee80211_is_ctl(fc))
-                               /*
-                                * Sometimes, we get invalid
-                                * MIC failures on valid control frames.
-                                * Remove these mic errors.
-                                */
-                               rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
-                       else
+                       /*
+                        * The MIC error bit is only valid if the frame
+                        * is not a control frame or fragment, and it was
+                        * decrypted using a valid TKIP key.
+                        */
+                       if (!ieee80211_is_ctl(fc) &&
+                           !ieee80211_has_morefrags(fc) &&
+                           !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
+                           test_bit(rx_stats->rs_keyix, common->tkip_keymap))
                                rxs->flag |= RX_FLAG_MMIC_ERROR;
+                       else
+                               rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
                }
                /*
                 * Reject error frames with the exception of
index d116229c334768ea3d58b8e4814acdaa2a1ad3d5..2466c0a52e5d12f548528673f39337b2b1de11eb 100644 (file)
@@ -3092,6 +3092,8 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
        struct b43_phy_n *nphy = phy->n;
        u16 buf[16];
 
+       nphy->phyrxchain = mask;
+
        if (0 /* FIXME clk */)
                return;
 
@@ -3103,7 +3105,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
        b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
                        (mask & 0x3) << B43_NPHY_RFSEQCA_RXEN_SHIFT);
 
-       if (mask & 0x3 != 0x3) {
+       if ((mask & 0x3) != 0x3) {
                b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 1);
                if (dev->phy.rev >= 3) {
                        /* TODO */
index 3bf5a30828be0370e71b0396ffefc65ae792743a..674fb93ae17f0829d02906173326f7b59e98e15c 100644 (file)
@@ -130,7 +130,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -217,7 +217,7 @@ static struct iwl_lib_ops iwl1000_lib = {
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index 7c731a79363252915243fc01350b8077b50bce58..65b5834da28c719b516fb8e55c022ad1beed08e7 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-3945-hw.h) only for hardware-related definitions.
- * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-commands.h for uCode API definitions.
  * Please use iwl-3945.h for driver implementation definitions.
  */
 
@@ -226,6 +226,7 @@ struct iwl3945_eeprom {
 
 /* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
 #define IWL39_NUM_QUEUES        5
+#define IWL39_CMD_QUEUE_NUM    4
 
 #define IWL_DEFAULT_TX_RETRY  15
 
index 8e84a08ff9519ae28031853c62cf3941adf0e93e..d707f5bb1a8b88f3678c3bad53032597691206a4 100644 (file)
@@ -343,7 +343,7 @@ void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 s
        int i;
 
        IWL_DEBUG_INFO(priv, "enter\n");
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
                goto out;
 
        psta = (struct iwl3945_sta_priv *) sta->drv_priv;
@@ -932,7 +932,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
        rcu_read_lock();
 
-       sta = ieee80211_find_sta(priv->vif,
+       sta = ieee80211_find_sta(priv->contexts[IWL_RXON_CTX_BSS].vif,
                                 priv->stations[sta_id].sta.sta.addr);
        if (!sta) {
                IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n");
@@ -949,7 +949,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
        switch (priv->band) {
        case IEEE80211_BAND_2GHZ:
                /* TODO: this always does G, not a regression */
-               if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+               if (priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_TGG_PROTECT_MSK) {
                        rs_sta->tgg = 1;
                        rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot;
                } else
index 8ccfcd08218d894895524c3995fca28f2695aa6c..5d09686c33895c89c7cb8d91124cc6f539cd2c80 100644 (file)
@@ -245,7 +245,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
                break;
        case IEEE80211_BAND_2GHZ:
                if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
-                   iwl_is_associated(priv)) {
+                   iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                        if (rate == IWL_RATE_11M_INDEX)
                                next_rate = IWL_RATE_5M_INDEX;
                }
@@ -273,7 +273,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
        struct iwl_queue *q = &txq->q;
        struct iwl_tx_info *tx_info;
 
-       BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);
+       BUG_ON(txq_id == IWL39_CMD_QUEUE_NUM);
 
        for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
@@ -285,7 +285,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
        }
 
        if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
-                       (txq_id != IWL_CMD_QUEUE_NUM) &&
+                       (txq_id != IWL39_CMD_QUEUE_NUM) &&
                        priv->mac80211_registered)
                iwl_wake_queue(priv, txq_id);
 }
@@ -760,7 +760,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                data_retry_limit = IWL_DEFAULT_TX_RETRY;
        tx_cmd->data_retry_limit = data_retry_limit;
 
-       if (tx_id >= IWL_CMD_QUEUE_NUM)
+       if (tx_id >= IWL39_CMD_QUEUE_NUM)
                rts_retry_limit = 3;
        else
                rts_retry_limit = 7;
@@ -909,7 +909,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 
        /* Tx queue(s) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+               slots_num = (txq_id == IWL39_CMD_QUEUE_NUM) ?
                                TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
                                       txq_id);
@@ -1072,7 +1072,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
        if (priv->txq)
                for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
                     txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                       if (txq_id == IWL39_CMD_QUEUE_NUM)
                                iwl_cmd_queue_free(priv);
                        else
                                iwl_tx_queue_free(priv, txq_id);
@@ -1439,17 +1439,18 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
        int rate_idx, i;
        const struct iwl_channel_info *ch_info = NULL;
        struct iwl3945_txpowertable_cmd txpower = {
-               .channel = priv->active_rxon.channel,
+               .channel = priv->contexts[IWL_RXON_CTX_BSS].active.channel,
        };
+       u16 chan;
+
+       chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel);
 
        txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
-       ch_info = iwl_get_channel_info(priv,
-                                      priv->band,
-                                      le16_to_cpu(priv->active_rxon.channel));
+       ch_info = iwl_get_channel_info(priv, priv->band, chan);
        if (!ch_info) {
                IWL_ERR(priv,
                        "Failed to get channel info for channel %d [%d]\n",
-                       le16_to_cpu(priv->active_rxon.channel), priv->band);
+                       chan, priv->band);
                return -EINVAL;
        }
 
@@ -1710,7 +1711,8 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
        return 0;
 }
 
-static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx)
 {
        int rc = 0;
        struct iwl_rx_packet *pkt;
@@ -1721,8 +1723,8 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
                .flags = CMD_WANT_SKB,
                .data = &rxon_assoc,
        };
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1732,10 +1734,10 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved = 0;
 
        rc = iwl_send_cmd_sync(priv, &cmd);
@@ -1761,14 +1763,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl3945_commit_rxon(struct iwl_priv *priv)
+static int iwl3945_commit_rxon(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
 {
        /* cast away the const for active_rxon in this function */
-       struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
-       struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
+       struct iwl3945_rxon_cmd *active_rxon = (void *)&ctx->active;
+       struct iwl3945_rxon_cmd *staging_rxon = (void *)&ctx->staging;
        int rc = 0;
-       bool new_assoc =
-               !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+       bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
 
        if (!iwl_is_alive(priv))
                return -1;
@@ -1781,7 +1783,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
            ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
        staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
 
-       rc = iwl_check_rxon_cmd(priv);
+       rc = iwl_check_rxon_cmd(priv, ctx);
        if (rc) {
                IWL_ERR(priv, "Invalid RXON configuration.  Not committing.\n");
                return -EINVAL;
@@ -1790,8 +1792,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        /* If we don't need to send a full RXON, we can use
         * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
-       if (!iwl_full_rxon_required(priv)) {
-               rc = iwl_send_rxon_assoc(priv);
+       if (!iwl_full_rxon_required(priv, &priv->contexts[IWL_RXON_CTX_BSS])) {
+               rc = iwl_send_rxon_assoc(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
                if (rc) {
                        IWL_ERR(priv, "Error setting RXON_ASSOC "
                                  "configuration (%d).\n", rc);
@@ -1807,7 +1810,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
         * before we apply the new config */
-       if (iwl_is_associated(priv) && new_assoc) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && new_assoc) {
                IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
@@ -1819,7 +1822,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                active_rxon->reserved5 = 0;
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
                                      sizeof(struct iwl3945_rxon_cmd),
-                                     &priv->active_rxon);
+                                     &priv->contexts[IWL_RXON_CTX_BSS].active);
 
                /* If the mask clearing failed then we set
                 * active_rxon back to what it was previously */
@@ -1829,8 +1832,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                                  "configuration (%d).\n", rc);
                        return rc;
                }
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
+               iwl_clear_ucode_stations(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
+               iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -1848,7 +1852,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        staging_rxon->reserved4 = 0;
        staging_rxon->reserved5 = 0;
 
-       iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
+       iwl_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto);
 
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -1862,8 +1866,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
        if (!new_assoc) {
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
+               iwl_clear_ucode_stations(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
+               iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
        }
 
        /* If we issue a new RXON command which required a tune then we must
@@ -2302,8 +2307,10 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
        int ret;
 
        if (add) {
-               ret = iwl_add_bssid_station(priv, vif->bss_conf.bssid, false,
-                                           &vif_priv->ibss_bssid_sta_id);
+               ret = iwl_add_bssid_station(
+                               priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                               vif->bss_conf.bssid, false,
+                               &vif_priv->ibss_bssid_sta_id);
                if (ret)
                        return ret;
 
@@ -2366,7 +2373,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
                 * 1M CCK rates */
 
                if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
-                   iwl_is_associated(priv)) {
+                   iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
 
                        index = IWL_FIRST_CCK_RATE;
                        for (i = IWL_RATE_6M_INDEX_TABLE;
@@ -2421,7 +2428,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
        priv->hw_params.max_stations = IWL3945_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL3945_BROADCAST_ID;
+
+       priv->sta_key_max_num = STA_KEY_MAX_NUM;
 
        priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
        priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
@@ -2439,7 +2448,8 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
        tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+       tx_beacon_cmd->tx.sta_id =
+               priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
        tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        frame_size = iwl3945_fill_beacon_frame(priv,
index f0a47f42d4b83069ad124e7d1489224122569c8a..1d6a46d4db594dbf9fe8ae34f4dc702ebb05063f 100644 (file)
@@ -347,7 +347,7 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
        struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
 
        if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-            iwl_is_associated(priv)) {
+           iwl_is_any_associated(priv)) {
                struct iwl_calib_diff_gain_cmd cmd;
 
                /* clear data for chain noise calibration algorithm */
@@ -576,7 +576,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
        /* Activate all Tx DMA/FIFO channels */
        priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
 
-       iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+       iwl4965_set_wr_ptrs(priv, IWL_DEFAULT_CMD_QUEUE_NUM, 0);
 
        /* make sure all queue are not stopped */
        memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
@@ -587,6 +587,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
        priv->txq_ctx_active_msk = 0;
        /* Map each Tx/cmd queue to its corresponding fifo */
        BUILD_BUG_ON(ARRAY_SIZE(default_queue_to_tx_fifo) != 7);
+
        for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
                int ac = default_queue_to_tx_fifo[i];
 
@@ -656,7 +657,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwl4965_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL4965_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL4965_BROADCAST_ID;
        priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
        priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
@@ -1374,6 +1375,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
        u8 band = 0;
        bool is_ht40 = false;
        u8 ctrl_chan_high = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (test_bit(STATUS_SCANNING, &priv->status)) {
                /* If this gets hit a lot, switch it to a BUG() and catch
@@ -1385,17 +1387,16 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
 
        band = priv->band == IEEE80211_BAND_2GHZ;
 
-       is_ht40 =  is_ht40_channel(priv->active_rxon.flags);
+       is_ht40 = is_ht40_channel(ctx->active.flags);
 
-       if (is_ht40 &&
-           (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+       if (is_ht40 && (ctx->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
                ctrl_chan_high = 1;
 
        cmd.band = band;
-       cmd.channel = priv->active_rxon.channel;
+       cmd.channel = ctx->active.channel;
 
        ret = iwl4965_fill_txpower_tbl(priv, band,
-                               le16_to_cpu(priv->active_rxon.channel),
+                               le16_to_cpu(ctx->active.channel),
                                is_ht40, ctrl_chan_high, &cmd.tx_power);
        if (ret)
                goto out;
@@ -1406,12 +1407,13 @@ out:
        return ret;
 }
 
-static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx)
 {
        int ret = 0;
        struct iwl4965_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1426,16 +1428,16 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved = 0;
        rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+           ctx->staging.ofdm_ht_single_stream_basic_rates;
        rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+           ctx->staging.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
 
        ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
@@ -1448,6 +1450,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
 static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int rc;
        u8 band = 0;
        bool is_ht40 = false;
@@ -1458,22 +1461,22 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        band = priv->band == IEEE80211_BAND_2GHZ;
 
-       is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
+       is_ht40 = is_ht40_channel(ctx->staging.flags);
 
        if (is_ht40 &&
-           (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+           (ctx->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
                ctrl_chan_high = 1;
 
        cmd.band = band;
        cmd.expect_beacon = 0;
        ch = ch_switch->channel->hw_value;
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -1508,7 +1511,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
 
@@ -2007,7 +2010,7 @@ static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
                start = IWL_STA_ID;
 
        if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
+               return priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        for (i = start; i < priv->hw_params.max_stations; i++)
@@ -2280,7 +2283,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index 146e6431ae950686b266f6d42f38c42b2be06470..3975e45e750065fd76df7417a441208184e7a1d4 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-5000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
  */
 
 #ifndef __iwl_5000_hw_h__
index 013f3dae69f107c35657c43631925461908e4463..1dbb1246c083e98ed54f8d5f016794f74b5ee1be 100644 (file)
@@ -180,7 +180,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -227,7 +227,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -275,14 +275,19 @@ static void iwl5150_temperature(struct iwl_priv *priv)
 static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl5000_channel_switch_cmd cmd;
        const struct iwl_channel_info *ch_info;
        u32 switch_time_in_usec, ucode_switch_time;
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
                .len = sizeof(cmd),
@@ -293,10 +298,10 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
        ch = ch_switch->channel->hw_value;
        IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-               priv->active_rxon.channel, ch);
+                     ctx->active.channel, ch);
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -331,7 +336,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
        priv->switch_rxon.channel = cmd.channel;
@@ -393,7 +398,7 @@ static struct iwl_lib_ops iwl5000_lib = {
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -464,7 +469,7 @@ static struct iwl_lib_ops iwl5150_lib = {
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index ddba39999997a05027b78b4b44f95ed302eba422..47891e16a75805f3d8c40ba98ae01099a58d0e27 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-6000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
  */
 
 #ifndef __iwl_6000_hw_h__
index 9e390f698641744860b06e8bf92f8a03a3fbddd6..2fdba088bd276d5c3ef5fb7f31b6944a0be4e911 100644 (file)
@@ -52,7 +52,7 @@
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
 #define IWL6050_UCODE_API_MAX 4
-#define IWL6000G2_UCODE_API_MAX 4
+#define IWL6000G2_UCODE_API_MAX 5
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 4
@@ -161,7 +161,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
@@ -198,14 +198,19 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl6000_channel_switch_cmd cmd;
        const struct iwl_channel_info *ch_info;
        u32 switch_time_in_usec, ucode_switch_time;
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
                .len = sizeof(cmd),
@@ -216,10 +221,10 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
        ch = ch_switch->channel->hw_value;
        IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-                     priv->active_rxon.channel, ch);
+                     ctx->active.channel, ch);
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -254,7 +259,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
        priv->switch_rxon.channel = cmd.channel;
@@ -318,7 +323,82 @@ static struct iwl_lib_ops iwl6000_lib = {
                .set_calib_version = iwl6000_set_calib_version,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+               .bt_stats_read = iwl_ucode_bt_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
+       .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
+};
+
+static struct iwl_lib_ops iwl6000g2b_lib = {
+       .set_hw_params = iwl6000_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
+       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+       .txq_free_tfd = iwl_hw_txq_free_tfd,
+       .txq_init = iwl_hw_tx_queue_init,
+       .rx_handler_setup = iwlagn_bt_rx_handler_setup,
+       .setup_deferred_work = iwlagn_bt_setup_deferred_work,
+       .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
+       .dump_nic_event_log = iwl_dump_nic_event_log,
+       .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
+       .dump_fh = iwl_dump_fh,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
+       .update_chain_flags = iwl_update_chain_flags,
+       .set_channel_switch = iwl6000_hw_channel_switch,
+       .apm_ops = {
+               .init = iwl_apm_init,
+               .stop = iwl_apm_stop,
+               .config = iwl6000_nic_config,
+               .set_pwr_src = iwl_set_pwr_src,
+       },
+       .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
+               },
+               .verify_signature  = iwlcore_eeprom_verify_signature,
+               .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+               .release_semaphore = iwlcore_eeprom_release_semaphore,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
+               .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+       },
+       .post_associate = iwl_post_associate,
+       .isr = iwl_isr_ict,
+       .config_ap = iwl_config_ap,
+       .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,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -344,21 +424,9 @@ static const struct iwl_ops iwl6000_ops = {
        .led = &iwlagn_led_ops,
 };
 
-static void do_not_send_bt_config(struct iwl_priv *priv)
-{
-}
-
-static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
-       .rxon_assoc = iwlagn_send_rxon_assoc,
-       .commit_rxon = iwl_commit_rxon,
-       .set_rxon_chain = iwl_set_rxon_chain,
-       .set_tx_ant = iwlagn_send_tx_ant_config,
-       .send_bt_config = do_not_send_bt_config,
-};
-
 static const struct iwl_ops iwl6000g2b_ops = {
-       .lib = &iwl6000_lib,
-       .hcmd = &iwl6000g2b_hcmd,
+       .lib = &iwl6000g2b_lib,
+       .hcmd = &iwlagn_bt_hcmd,
        .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
@@ -499,7 +567,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -507,6 +575,11 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .chain_noise_calib_by_driver = true,
        .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 = {
@@ -535,7 +608,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -543,6 +616,11 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .chain_noise_calib_by_driver = true,
        .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 = {
@@ -573,7 +651,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -581,6 +659,11 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .chain_noise_calib_by_driver = true,
        .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 = {
@@ -609,7 +692,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -617,6 +700,11 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .chain_noise_calib_by_driver = true,
        .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 = {
@@ -647,7 +735,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -655,6 +743,11 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .chain_noise_calib_by_driver = true,
        .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 = {
@@ -683,7 +776,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .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,
@@ -691,6 +784,11 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .chain_noise_calib_by_driver = true,
        .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,
 };
 
 /*
index c4c5691032a601a0dcc34e9d7f44fa8f81f1eab2..84ad62958535ed455ac4d32e2b5501efb9e5d6da 100644 (file)
@@ -625,7 +625,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
 
        data = &(priv->sensitivity_data);
 
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_any_associated(priv)) {
                IWL_DEBUG_CALIB(priv, "<< - not associated\n");
                return;
        }
@@ -763,6 +763,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
        unsigned long flags;
        struct statistics_rx_non_phy *rx_info;
        u8 first_chain;
+       /*
+        * MULTI-FIXME:
+        * When we support multiple interfaces on different channels,
+        * this must be modified/fixed.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (priv->disable_chain_noise_cal)
                return;
@@ -793,8 +799,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
                return;
        }
 
-       rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
-       rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
+       rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
+       rxon_chnum = le16_to_cpu(ctx->staging.channel);
        if (priv->cfg->bt_statistics) {
                stat_band24 = !!(((struct iwl_bt_notif_statistics *)
                                 stat_resp)->flag &
@@ -914,7 +920,11 @@ 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.
         */
-       active_chains &= priv->hw_params.valid_rx_ant;
+       if (priv->cfg->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
+               active_chains &= priv->hw_params.valid_rx_ant;
 
        num_tx_chains = 0;
        for (i = 0; i < NUM_RX_CHAINS; i++) {
index 84939763d178502b3bc3ec605c1d9e64c6a8032b..6fb52abafc8d46e305328754564d25827cd8a16a 100644 (file)
 #include "iwl-io.h"
 #include "iwl-agn.h"
 
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx)
 {
        int ret = 0;
        struct iwl5000_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -60,23 +61,23 @@ int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved1 = 0;
        rxon_assoc.reserved2 = 0;
        rxon_assoc.reserved3 = 0;
        rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+           ctx->staging.ofdm_ht_single_stream_basic_rates;
        rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+           ctx->staging.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
        rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
-       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+                ctx->staging.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
 
-       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+       ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
        if (ret)
                return ret;
@@ -184,7 +185,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
        int ret;
 
        if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-            iwl_is_associated(priv)) {
+           iwl_is_any_associated(priv)) {
                struct iwl_calib_chain_noise_reset_cmd cmd;
 
                /* clear data for chain noise calibration algorithm */
@@ -269,12 +270,95 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 }
 
+static int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+       struct iwl_wipan_params_cmd cmd;
+       struct iwl_rxon_context *ctx_bss, *ctx_pan;
+       int slot0 = 300, slot1 = 0;
+       int ret;
+
+       if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+               return 0;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       lockdep_assert_held(&priv->mutex);
+
+       ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+       ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       /* only 2 slots are currently allowed */
+       cmd.num_slots = 2;
+
+       cmd.slots[0].type = 0; /* BSS */
+       cmd.slots[1].type = 1; /* PAN */
+
+       if (ctx_bss->vif && ctx_pan->vif) {
+               int bcnint = ctx_pan->vif->bss_conf.beacon_int;
+
+               /* should be set, but seems unused?? */
+               cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+               if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+                   bcnint &&
+                   bcnint != ctx_bss->vif->bss_conf.beacon_int) {
+                       IWL_ERR(priv,
+                               "beacon intervals don't match (%d, %d)\n",
+                               ctx_bss->vif->bss_conf.beacon_int,
+                               ctx_pan->vif->bss_conf.beacon_int);
+               } else
+                       bcnint = max_t(int, bcnint,
+                                      ctx_bss->vif->bss_conf.beacon_int);
+               if (!bcnint)
+                       bcnint = 100;
+               slot0 = bcnint / 2;
+               slot1 = bcnint - slot0;
+
+               if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+                   (!ctx_bss->vif->bss_conf.idle &&
+                    !ctx_bss->vif->bss_conf.assoc)) {
+                       slot0 = bcnint * 3 - 20;
+                       slot1 = 20;
+               } else if (!ctx_pan->vif->bss_conf.idle &&
+                           !ctx_pan->vif->bss_conf.assoc) {
+                       slot1 = bcnint * 3 - 20;
+                       slot0 = 20;
+               }
+       } else if (ctx_pan->vif) {
+               slot0 = 0;
+               slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+                                       ctx_pan->vif->bss_conf.beacon_int;
+               slot1 = max_t(int, 100, slot1);
+       }
+
+       cmd.slots[0].width = cpu_to_le16(slot0);
+       cmd.slots[1].width = cpu_to_le16(slot1);
+
+       ret = iwl_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+       return ret;
+}
+
 struct iwl_hcmd_ops iwlagn_hcmd = {
        .rxon_assoc = iwlagn_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
        .set_rxon_chain = iwl_set_rxon_chain,
        .set_tx_ant = iwlagn_send_tx_ant_config,
        .send_bt_config = iwl_send_bt_config,
+       .set_pan_params = iwlagn_set_pan_params,
+};
+
+struct iwl_hcmd_ops iwlagn_bt_hcmd = {
+       .rxon_assoc = iwlagn_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+       .set_tx_ant = iwlagn_send_tx_ant_config,
+       .send_bt_config = iwlagn_send_advance_bt_config,
+       .set_pan_params = iwlagn_set_pan_params,
 };
 
 struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
index eedd71f5506b3b2c4dbd4e19be070fe70ba4667a..a8f2adfd799e790e009192a5bed1594ed602e87c 100644 (file)
@@ -247,7 +247,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
                struct iwl_ht_agg *agg;
 
                agg = &priv->stations[sta_id].tid[tid].agg;
-
+               /*
+                * If the BT kill count is non-zero, we'll get this
+                * notification again.
+                */
+               if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
+                   priv->cfg->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);
 
                /* check if BAR is needed */
@@ -1156,6 +1163,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        };
        struct iwl_scan_cmd *scan;
        struct ieee80211_conf *conf = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 rate_flags = 0;
        u16 cmd_len;
        u16 rx_chain = 0;
@@ -1168,6 +1176,9 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        u8 active_chains;
        u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
 
+       if (vif)
+               ctx = iwl_rxon_ctx_from_vif(vif);
+
        conf = ieee80211_get_hw_conf(priv->hw);
 
        cancel_delayed_work(&priv->scan_check);
@@ -1225,7 +1236,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
        scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                u16 interval = 0;
                u32 extra;
                u32 suspend_time = 100;
@@ -1276,13 +1287,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
 
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        switch (priv->scan_band) {
        case IEEE80211_BAND_2GHZ:
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
+               chan_mod = le32_to_cpu(
+                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_CHANNEL_MODE_MSK)
                                       >> RXON_FLG_CHANNEL_MODE_POS;
                if (chan_mod == CHANNEL_MODE_PURE_40) {
                        rate = IWL_RATE_6M_PLCP;
@@ -1290,6 +1303,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        rate = IWL_RATE_1M_PLCP;
                        rate_flags = RATE_MCS_CCK_MSK;
                }
+               /*
+                * 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)
+                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
                scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
                break;
        case IEEE80211_BAND_5GHZ:
@@ -1327,6 +1346,12 @@ void 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) {
+               /* operated as 1x1 in full concurrency mode */
+               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],
                                                    scan_tx_antennas);
        rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
@@ -1345,6 +1370,11 @@ void 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) {
+               /* operated as 1x1 in full concurrency mode */
+               rx_ant = first_antenna(rx_ant);
+       }
+
        /* MIMO is not used here, but value is required */
        rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
        rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
@@ -1394,6 +1424,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->len = cpu_to_le16(cmd.len);
 
        set_bit(STATUS_SCAN_HW, &priv->status);
+
+       if (priv->cfg->ops->hcmd->set_pan_params &&
+           priv->cfg->ops->hcmd->set_pan_params(priv))
+               goto done;
+
        if (iwl_send_cmd_sync(priv, &cmd))
                goto done;
 
@@ -1420,7 +1455,8 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 
        if (add)
-               return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true,
+               return iwl_add_bssid_station(priv, vif_priv->ctx,
+                                            vif->bss_conf.bssid, true,
                                             &vif_priv->ibss_bssid_sta_id);
        return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
                                  vif->bss_conf.bssid);
@@ -1453,7 +1489,7 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
 
        /* waiting for all the tx frames complete might take a while */
        for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
-               if (cnt == IWL_CMD_QUEUE_NUM)
+               if (cnt == priv->cmd_queue)
                        continue;
                txq = &priv->txq[cnt];
                q = &txq->q;
@@ -1518,3 +1554,377 @@ done:
        ieee80211_wake_queues(priv->hw);
        mutex_unlock(&priv->mutex);
 }
+
+/*
+ * BT coex
+ */
+/*
+ * Macros to access the lookup table.
+ *
+ * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req,
+* wifi_prio, wifi_txrx and wifi_sh_ant_req.
+ *
+ * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH
+ *
+ * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits
+ * one after another in 32-bit registers, and "registers" 0 through 7 contain
+ * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order).
+ *
+ * These macros encode that format.
+ */
+#define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \
+                 wifi_txrx, wifi_sh_ant_req) \
+       (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \
+       (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6))
+
+#define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \
+       lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f)))
+#define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                                wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \
+                                  bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                                  wifi_sh_ant_req))))
+#define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                               wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \
+                              bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                              wifi_sh_ant_req))
+#define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \
+                                 wifi_req, wifi_prio, wifi_txrx, \
+                                 wifi_sh_ant_req) \
+       LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \
+                              bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                              wifi_sh_ant_req))
+
+#define LUT_WLAN_KILL_OP(lut, op, val) \
+       lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e)))
+#define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                          wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                            wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))))
+#define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                         wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                        wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                           wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                        wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+#define LUT_ANT_SWITCH_OP(lut, op, val) \
+       lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1)))
+#define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                           wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                             wifi_req, wifi_prio, wifi_txrx, \
+                             wifi_sh_ant_req))))
+#define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                          wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                         wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                            wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                         wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+static const __le32 iwlagn_def_3w_lookup[12] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xc0004000),
+       cpu_to_le32(0x00004000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0004000),
+};
+
+static const __le32 iwlagn_concurrent_lookup[12] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+};
+
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
+{
+       struct iwlagn_bt_cmd bt_cmd = {
+               .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
+               .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
+               .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
+               .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
+       };
+
+       BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
+                       sizeof(bt_cmd.bt3_lookup_table));
+
+       bt_cmd.prio_boost = priv->cfg->bt_prio_boost;
+       bt_cmd.kill_ack_mask = priv->kill_ack_mask;
+       bt_cmd.kill_cts_mask = priv->kill_cts_mask;
+       bt_cmd.valid = priv->bt_valid;
+
+       /*
+        * Configure BT coex mode to "no coexistence" when the
+        * user disabled BT coexistence, we have no interface
+        * (might be in monitor mode), or the interface is in
+        * IBSS mode (no proper uCode support for coex then).
+        */
+       if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) {
+               bt_cmd.flags = 0;
+       } else {
+               bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
+                                       IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+               if (priv->bt_ch_announce)
+                       bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
+               IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags);
+       }
+       if (priv->bt_full_concurrent)
+               memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup,
+                       sizeof(iwlagn_concurrent_lookup));
+       else
+               memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup,
+                       sizeof(iwlagn_def_3w_lookup));
+
+       IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n",
+                      bt_cmd.flags ? "active" : "disabled",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd))
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
+
+       /*
+        * When we are doing a restart, need to also reconfigure BT
+        * SCO to the device. If not doing a restart, bt_sco_active
+        * will always be false, so there's no need to have an extra
+        * variable to check for it.
+        */
+       if (priv->bt_sco_active) {
+               struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+
+               if (priv->bt_sco_active)
+                       sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+               if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO,
+                                    sizeof(sco_cmd), &sco_cmd))
+                       IWL_ERR(priv, "failed to send BT SCO command\n");
+       }
+}
+
+static void iwlagn_bt_traffic_change_work(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_traffic_change_work);
+       struct iwl_rxon_context *ctx;
+       int smps_request = -1;
+
+       IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n",
+                      priv->bt_traffic_load);
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               smps_request = IEEE80211_SMPS_AUTOMATIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               smps_request = IEEE80211_SMPS_DYNAMIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               smps_request = IEEE80211_SMPS_STATIC;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT traffic load: %d\n",
+                       priv->bt_traffic_load);
+               break;
+       }
+
+       mutex_lock(&priv->mutex);
+
+       if (priv->cfg->ops->lib->update_chain_flags)
+               priv->cfg->ops->lib->update_chain_flags(priv);
+
+       if (smps_request != -1) {
+               for_each_context(priv, ctx) {
+                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
+                               ieee80211_request_smps(ctx->vif, smps_request);
+               }
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwlagn_print_uartmsg(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
+{
+       IWL_DEBUG_NOTIF(priv, "Message Type = 0x%X, SSN = 0x%X, "
+                       "Update Req = 0x%X",
+               (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1MSGTYPE_POS,
+               (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1SSN_POS,
+               (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1UPDATEREQ_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
+                       "Chl_SeqN = 0x%X, In band = 0x%X",
+               (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
+               (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
+               (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2CHLSEQN_POS,
+               (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2INBAND_POS);
+
+       IWL_DEBUG_NOTIF(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
+                       "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X",
+               (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SCOESCO_POS,
+               (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SNIFF_POS,
+               (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3A2DP_POS,
+               (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3ACL_POS,
+               (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3MASTER_POS,
+               (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3OBEX_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Idle duration = 0x%X",
+               (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
+                       BT_UART_MSG_FRAME4IDLEDURATION_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
+                       "eSCO Retransmissions = 0x%X",
+               (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5TXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5RXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X",
+               (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
+               (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6DISCOVERABLE_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = "
+                       "0x%X, Connectable = 0x%X",
+               (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
+               (BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS,
+               (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7CONNECTABLE_POS);
+}
+
+static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv,
+                                    struct iwl_bt_uart_msg *uart_msg)
+{
+       u8 kill_ack_msk;
+       __le32 bt_kill_ack_msg[2] = {
+                       cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) };
+
+       kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK |
+                       BT_UART_MSG_FRAME3SNIFF_MSK |
+                       BT_UART_MSG_FRAME3SCOESCO_MSK) &
+                       uart_msg->frame3) == 0) ? 1 : 0;
+       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) {
+               priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
+               priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk];
+               /* schedule to send runtime bt_config */
+               queue_work(priv->workqueue, &priv->bt_runtime_config);
+       }
+
+}
+
+void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                            struct iwl_rx_mem_buffer *rxb)
+{
+       unsigned long flags;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
+       struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+       struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
+       u8 last_traffic_load;
+
+       IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n");
+       IWL_DEBUG_NOTIF(priv, "    status: %d\n", coex->bt_status);
+       IWL_DEBUG_NOTIF(priv, "    traffic load: %d\n", coex->bt_traffic_load);
+       IWL_DEBUG_NOTIF(priv, "    CI compliance: %d\n",
+                       coex->bt_ci_compliance);
+       iwlagn_print_uartmsg(priv, uart_msg);
+
+       last_traffic_load = priv->notif_bt_traffic_load;
+       priv->notif_bt_traffic_load = coex->bt_traffic_load;
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+               if (priv->bt_status != coex->bt_status ||
+                   last_traffic_load != coex->bt_traffic_load) {
+                       if (coex->bt_status) {
+                               /* BT on */
+                               if (!priv->bt_ch_announce)
+                                       priv->bt_traffic_load =
+                                               IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                               else
+                                       priv->bt_traffic_load =
+                                               coex->bt_traffic_load;
+                       } else {
+                               /* BT off */
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+                       }
+                       priv->bt_status = coex->bt_status;
+                       queue_work(priv->workqueue,
+                                  &priv->bt_traffic_change_work);
+               }
+               if (priv->bt_sco_active !=
+                   (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) {
+                       priv->bt_sco_active = uart_msg->frame3 &
+                               BT_UART_MSG_FRAME3SCOESCO_MSK;
+                       if (priv->bt_sco_active)
+                               sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+                       iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO,
+                                      sizeof(sco_cmd), &sco_cmd, NULL);
+               }
+       }
+
+       iwlagn_set_kill_ack_msk(priv, uart_msg);
+
+       /* FIXME: based on notification, adjust the prio_boost */
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->bt_ci_compliance = coex->bt_ci_compliance;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
+{
+       iwlagn_rx_handler_setup(priv);
+       priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
+               iwlagn_bt_coex_profile_notif;
+}
+
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
+{
+       iwlagn_setup_deferred_work(priv);
+
+       INIT_WORK(&priv->bt_traffic_change_work,
+                 iwlagn_bt_traffic_change_work);
+}
+
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
+{
+       cancel_work_sync(&priv->bt_traffic_change_work);
+}
index a4563389bad0db18eb5f2106903e85c3521f6ad2..57629fba3a7ddbb17fd013ac7623b283a6d0d57a 100644 (file)
@@ -82,7 +82,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                                   struct iwl_lq_sta *lq_sta);
 static void rs_fill_link_cmd(struct iwl_priv *priv,
                             struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
 
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -301,7 +301,19 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                                      struct ieee80211_sta *sta)
 {
        int ret = -EAGAIN;
-       u32 load = rs_tl_get_load(lq_data, tid);
+       u32 load;
+
+       /*
+        * Don't create TX aggregation sessions when in high
+        * BT traffic, as they would just be disrupted by BT.
+        */
+       if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+               IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+                       priv->bt_traffic_load);
+               return ret;
+       }
+
+       load = rs_tl_get_load(lq_data, tid);
 
        if (load > IWL_AGG_LOAD_THRESHOLD) {
                IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
@@ -590,11 +602,13 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
  * Green-field mode is valid if the station supports it and
  * there are no non-GF stations present in the BSS.
  */
-static inline u8 rs_use_green(struct ieee80211_sta *sta,
-                             struct iwl_ht_config *ht_conf)
+static bool rs_use_green(struct ieee80211_sta *sta)
 {
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
        return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-               !(ht_conf->non_GF_STA_present);
+               !(ctx->ht.non_gf_sta_present);
 }
 
 /**
@@ -746,6 +760,32 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
                (a->is_SGI == b->is_SGI);
 }
 
+static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_scale_tbl_info *tbl;
+       bool full_concurrent;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
+               full_concurrent = true;
+       else
+               full_concurrent = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (priv->bt_full_concurrent != full_concurrent) {
+               priv->bt_full_concurrent = full_concurrent;
+
+               /* Update uCode's rate table. */
+               tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+               iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+
+               queue_work(priv->workqueue, &priv->bt_full_concurrency);
+       }
+}
+
 /*
  * mac80211 sends us Tx status
  */
@@ -765,6 +805,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        u32 tx_rate;
        struct iwl_scale_tbl_info tbl_type;
        struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
 
@@ -831,7 +873,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                lq_sta->missed_rate_counter++;
                if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
                        lq_sta->missed_rate_counter = 0;
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
                }
                /* Regardless, ignore this status info for outdated rate */
                return;
@@ -862,7 +904,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                 * no matching table found, let's by-pass the data collection
                 * and continue to perform rate scale to find the rate table
                 */
-               rs_stay_in_table(lq_sta);
+               rs_stay_in_table(lq_sta, true);
                goto done;
        }
 
@@ -928,6 +970,10 @@ done:
        /* See if there's a better rate or modulation mode to try. */
        if (sta && sta->supp_rates[sband->band])
                rs_rate_scale_perform(priv, skb, sta, lq_sta);
+
+       /* Is there a need to switch between full concurrency and 3-wire? */
+       if (priv->bt_ant_couple_ok)
+               rs_bt_update_lq(priv, ctx, lq_sta);
 }
 
 /*
@@ -1121,6 +1167,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
        u16 rate_mask;
        s32 rate;
        s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1141,7 +1189,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_SEARCH;
        rate_mask = lq_sta->active_mimo2_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1175,6 +1223,8 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
        u16 rate_mask;
        s32 rate;
        s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1195,7 +1245,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
        rate_mask = lq_sta->active_mimo3_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1230,6 +1280,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        u16 rate_mask;
        u8 is_green = lq_sta->is_green;
        s32 rate;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1242,7 +1294,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_SEARCH;
        rate_mask = lq_sta->active_siso_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1286,12 +1338,45 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
        int ret = 0;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+                   tbl->action != IWL_LEGACY_SWITCH_SISO)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (!iwl_ht_enabled(priv))
                /* stay in Legacy */
                tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
        else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
                   tbl->action > IWL_LEGACY_SWITCH_SISO)
                tbl->action = IWL_LEGACY_SWITCH_SISO;
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               if (!iwl_ht_enabled(priv))
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+       }
+
        start_action = tbl->action;
        for (; ;) {
                lq_sta->action_counter++;
@@ -1307,7 +1392,10 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                                break;
 
                        /* Don't change antenna if success has been great */
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
                                break;
 
                        /* Set up search table to try other antenna */
@@ -1425,11 +1513,41 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
            tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
                /* stay in SISO */
                tbl->action = IWL_SISO_SWITCH_ANTENNA1;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       }
+
        start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
@@ -1437,14 +1555,16 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                case IWL_SISO_SWITCH_ANTENNA1:
                case IWL_SISO_SWITCH_ANTENNA2:
                        IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
-
                        if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
-                                                       tx_chains_num <= 1) ||
+                                               tx_chains_num <= 1) ||
                            (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
-                                                       tx_chains_num <= 2))
+                                               tx_chains_num <= 2))
                                break;
 
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
                                break;
 
                        memcpy(search_tbl, tbl, sz);
@@ -1564,12 +1684,40 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
                /* switch in SISO */
                tbl->action = IWL_MIMO2_SWITCH_SISO_A;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO2_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+
        start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
@@ -1706,12 +1854,40 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
        int ret;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
                /* switch in SISO */
                tbl->action = IWL_MIMO3_SWITCH_SISO_A;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO3_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+
        start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
@@ -1839,7 +2015,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
  * 2) # times calling this function
  * 3) elapsed time in this mode (not used, for now)
  */
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
 {
        struct iwl_scale_tbl_info *tbl;
        int i;
@@ -1870,7 +2046,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
                 * allow a new search.  Also (below) reset all bitmaps and
                 * stats in active history.
                 */
-               if ((lq_sta->total_failed > lq_sta->max_failure_limit) ||
+               if (force_search ||
+                   (lq_sta->total_failed > lq_sta->max_failure_limit) ||
                    (lq_sta->total_success > lq_sta->max_success_limit) ||
                    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
                     && (flush_interval_passed))) {
@@ -1919,6 +2096,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
  * return rate_n_flags as used in the table
  */
 static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
                                struct iwl_lq_sta *lq_sta,
                                struct iwl_scale_tbl_info *tbl,
                                int index, u8 is_green)
@@ -1928,7 +2106,7 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
        /* Update uCode's rate table. */
        rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        rs_fill_link_cmd(priv, lq_sta, rate);
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
 
        return rate;
 }
@@ -1967,6 +2145,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        s32 sr;
        u8 tid = MAX_TID_COUNT;
        struct iwl_tid_data *tid_data;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
 
@@ -2005,7 +2185,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (is_legacy(tbl->lq_type))
                lq_sta->is_green = 0;
        else
-               lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+               lq_sta->is_green = rs_use_green(sta);
        is_green = lq_sta->is_green;
 
        /* current tx rate */
@@ -2044,7 +2224,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
                        /* get "active" rate info */
                        index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rate = rs_update_rate_tbl(priv, lq_sta,
+                       rate = rs_update_rate_tbl(priv, ctx, lq_sta,
                                                  tbl, index, is_green);
                }
                return;
@@ -2086,7 +2266,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
                /* Should we stay with this modulation mode,
                 * or search for a new one? */
-               rs_stay_in_table(lq_sta);
+               rs_stay_in_table(lq_sta, false);
 
                goto out;
        }
@@ -2234,6 +2414,28 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
                (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
                scale_action = -1;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+                       /*
+                        * don't set scale_action, don't want to scale up if
+                        * the rate scale doesn't otherwise think that is a
+                        * good idea.
+                        */
+               } else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
+                       scale_action = -1;
+               }
+       }
+       lq_sta->last_bt_traffic = priv->bt_traffic_load;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               /* search for a new modulation */
+               rs_stay_in_table(lq_sta, true);
+               goto lq_update;
+       }
+
        switch (scale_action) {
        case -1:
                /* Decrease starting rate, update uCode's rate table */
@@ -2264,13 +2466,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq)
-               rate = rs_update_rate_tbl(priv, lq_sta,
+               rate = rs_update_rate_tbl(priv, ctx, lq_sta,
                                          tbl, index, is_green);
 
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
                /* Should we stay with this modulation mode,
                 * or search for a new one? */
-               rs_stay_in_table(lq_sta);
+         rs_stay_in_table(lq_sta, false);
        }
        /*
         * Search for new modulation mode if we're:
@@ -2306,7 +2508,7 @@ lq_update:
                        IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
                                     tbl->current_rate, index);
                        rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
                } else
                        done_search = 1;
        }
@@ -2376,12 +2578,17 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        int rate_idx;
        int i;
        u32 rate;
-       u8 use_green = rs_use_green(sta, &priv->current_ht_config);
+       u8 use_green = rs_use_green(sta);
        u8 active_tbl = 0;
        u8 valid_tx_ant;
+       struct iwl_station_priv *sta_priv;
+       struct iwl_rxon_context *ctx;
 
        if (!sta || !lq_sta)
-               goto out;
+               return;
+
+       sta_priv = (void *)sta->drv_priv;
+       ctx = sta_priv->common.ctx;
 
        i = lq_sta->last_txrate_idx;
 
@@ -2413,9 +2620,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        rs_set_expected_tpt_table(lq_sta, tbl);
        rs_fill_link_cmd(NULL, lq_sta, rate);
        priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_SYNC, true);
- out:
-       return;
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
 }
 
 static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
@@ -2543,7 +2748,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
        lq_sta->is_dup = 0;
        lq_sta->max_rate_idx = -1;
        lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
-       lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+       lq_sta->is_green = rs_use_green(sta);
        lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
        lq_sta->band = priv->band;
        /*
@@ -2616,6 +2821,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
        rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
                                  &tbl_type, &rate_idx);
 
+       if (priv && priv->bt_full_concurrent) {
+               /* 1x1 only */
+               tbl_type.ant_type =
+                       first_antenna(priv->hw_params.valid_tx_ant);
+       }
+
        /* How many times should we repeat the initial rate? */
        if (is_legacy(tbl_type.lq_type)) {
                ant_toggle_cnt = 1;
@@ -2640,9 +2851,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
 
        index++;
        repeat_rate--;
-
-       if (priv)
-               valid_tx_ant = priv->hw_params.valid_tx_ant;
+       if (priv) {
+               if (priv->bt_full_concurrent)
+                       valid_tx_ant = ANT_A;
+               else
+                       valid_tx_ant = priv->hw_params.valid_tx_ant;
+       }
 
        /* Fill rest of rate table */
        while (index < LINK_QUAL_MAX_RETRY_NUM) {
@@ -2657,7 +2871,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
                                         rs_toggle_antenna(valid_tx_ant,
                                                        &new_rate, &tbl_type))
                                        ant_toggle_cnt = 1;
-}
+                       }
 
                        /* Override next rate if needed for debug purposes */
                        rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
@@ -2672,6 +2886,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
                rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
                                                &rate_idx);
 
+               if (priv && priv->bt_full_concurrent) {
+                       /* 1x1 only */
+                       tbl_type.ant_type =
+                               first_antenna(priv->hw_params.valid_tx_ant);
+               }
+
                /* Indicate to uCode which entries might be MIMO.
                 * If initial rate was MIMO, this will finally end up
                 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
@@ -2788,6 +3008,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
        char buf[64];
        int buf_size;
        u32 parsed_rate;
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        priv = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
@@ -2810,7 +3033,8 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 
        if (lq_sta->dbg_fixed_rate) {
                rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
+               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+                               false);
        }
 
        return count;
index 8292f6d48ec62067cb5dec7f4076038ad0b46430..3970ab1deaf99cbbe8c8437afd91315ac38705fe 100644 (file)
@@ -432,6 +432,8 @@ struct iwl_lq_sta {
        u32 last_rate_n_flags;
        /* packets destined for this STA are aggregated */
        u8 is_agg;
+       /* BT traffic this sta was last updated in */
+       u8 last_bt_traffic;
 };
 
 static inline u8 num_of_ant(u8 mask)
index 30298ea56a24ce6f06156f4e49d1037bb15830c3..07b2c6cadf5103a21b26b221b4e147085cbe64be 100644 (file)
@@ -416,18 +416,26 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
        /* stop ct_kill_waiting_tm timer */
        del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
        if (changed) {
-               struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-
                if (tt->state >= IWL_TI_1) {
                        /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
                        tt->tt_power_mode = IWL_POWER_INDEX_5;
-                       if (!iwl_ht_enabled(priv))
-                               /* disable HT */
-                               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-                                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-                                       RXON_FLG_HT40_PROT_MSK |
-                                       RXON_FLG_HT_PROT_MSK);
-                       else {
+
+                       if (!iwl_ht_enabled(priv)) {
+                               struct iwl_rxon_context *ctx;
+
+                               for_each_context(priv, ctx) {
+                                       struct iwl_rxon_cmd *rxon;
+
+                                       rxon = &ctx->staging;
+
+                                       /* disable HT */
+                                       rxon->flags &= ~(
+                                               RXON_FLG_CHANNEL_MODE_MSK |
+                                               RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+                                               RXON_FLG_HT40_PROT_MSK |
+                                               RXON_FLG_HT_PROT_MSK);
+                               }
+                       } else {
                                /* check HT capability and set
                                 * according to the system HT capability
                                 * in case get disabled before */
index 3fc982e879215d23412c9e97f2377cc259de2f0a..5950184d98606a4f997bc5b027b5ddd21b6db7f8 100644 (file)
@@ -71,18 +71,6 @@ static const u8 tid_to_ac[] = {
        2, 3, 3, 2, 1, 1, 0, 0
 };
 
-static const u8 ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-
-static inline int get_fifo_from_ac(u8 ac)
-{
-       return ac_to_fifo[ac];
-}
-
 static inline int get_ac_from_tid(u16 tid)
 {
        if (likely(tid < ARRAY_SIZE(tid_to_ac)))
@@ -92,10 +80,10 @@ static inline int get_ac_from_tid(u16 tid)
        return -EINVAL;
 }
 
-static inline int get_fifo_from_tid(u16 tid)
+static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid)
 {
        if (likely(tid < ARRAY_SIZE(tid_to_ac)))
-               return get_fifo_from_ac(tid_to_ac[tid]);
+               return ctx->ac_to_fifo[tid_to_ac[tid]];
 
        /* no support for TIDs 8-15 yet */
        return -EINVAL;
@@ -118,7 +106,7 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 
        WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       if (txq_id != IWL_CMD_QUEUE_NUM) {
+       if (txq_id != priv->cmd_queue) {
                sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
                sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
 
@@ -155,7 +143,7 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
 
        WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       if (txq_id != IWL_CMD_QUEUE_NUM)
+       if (txq_id != priv->cmd_queue)
                sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
 
        bc_ent = cpu_to_le16(1 | (sta_id << 12));
@@ -333,19 +321,15 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
        iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
 }
 
-static inline int get_queue_from_ac(u16 ac)
-{
-       return ac;
-}
-
 /*
  * handle build REPLY_TX command notification.
  */
 static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
-                                 struct iwl_tx_cmd *tx_cmd,
-                                 struct ieee80211_tx_info *info,
-                                 struct ieee80211_hdr *hdr,
-                                 u8 std_id)
+                                       struct sk_buff *skb,
+                                       struct iwl_tx_cmd *tx_cmd,
+                                       struct ieee80211_tx_info *info,
+                                       struct ieee80211_hdr *hdr,
+                                       u8 std_id)
 {
        __le16 fc = hdr->frame_control;
        __le32 tx_flags = tx_cmd->tx_flags;
@@ -365,6 +349,12 @@ 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 &&
+                (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
+                ieee80211_is_reassoc_req(fc) ||
+                skb->protocol == cpu_to_be16(ETH_P_PAE)))
+               tx_flags |= TX_CMD_FLG_IGNORE_BT;
 
 
        tx_cmd->sta_id = std_id;
@@ -454,7 +444,12 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
                rate_flags |= RATE_MCS_CCK_MSK;
 
        /* Set up antennas */
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+        if (priv->cfg->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));
+       } else
+               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
                                              priv->hw_params.valid_tx_ant);
        rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 
@@ -519,6 +514,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
        struct iwl_tx_cmd *tx_cmd;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int swq_id, txq_id;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
@@ -533,6 +529,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        u8 *qc = NULL;
        unsigned long flags;
 
+       if (info->control.vif)
+               ctx = iwl_rxon_ctx_from_vif(info->control.vif);
+
        spin_lock_irqsave(&priv->lock, flags);
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
@@ -553,7 +552,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -565,8 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (sta)
                sta_priv = (void *)sta->drv_priv;
 
-       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
-           sta_priv->asleep) {
+       if (sta_priv && sta_priv->asleep) {
                WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
                /*
                 * This sends an asynchronous command to the device,
@@ -580,7 +578,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
        }
 
-       txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+       /*
+        * Send this frame after DTIM -- there's a special queue
+        * reserved for this for contexts that support AP mode.
+        */
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+               txq_id = ctx->mcast_queue;
+               /*
+                * The microcode will clear the more data
+                * bit in the last frame it transmits.
+                */
+               hdr->frame_control |=
+                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       } else
+               txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
 
        /* irqs already disabled/saved above when locking priv->lock */
        spin_lock(&priv->sta_lock);
@@ -625,6 +636,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
        txq->txb[q->write_ptr].skb = skb;
+       txq->txb[q->write_ptr].ctx = ctx;
 
        /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[q->write_ptr];
@@ -655,7 +667,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
 
        /* TODO need this for burst mode later on */
-       iwlagn_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+       iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
        iwl_dbg_log_tx_data_frame(priv, len, hdr);
 
        iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
@@ -813,7 +825,7 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
        /* Tx queues */
        if (priv->txq) {
                for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                       if (txq_id == priv->cmd_queue)
                                iwl_cmd_queue_free(priv);
                        else
                                iwl_tx_queue_free(priv, txq_id);
@@ -870,9 +882,9 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* Alloc and init all Tx queues, including the command queue (#4) */
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+               slots_num = (txq_id == priv->cmd_queue) ?
                                        TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
                                       txq_id);
@@ -910,7 +922,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
 
        /* Alloc and init all Tx queues, including the command queue (#4) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+               slots_num = txq_id == priv->cmd_queue ?
                            TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
        }
@@ -968,7 +980,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        unsigned long flags;
        struct iwl_tid_data *tid_data;
 
-       tx_fifo = get_fifo_from_tid(tid);
+       tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
        if (unlikely(tx_fifo < 0))
                return tx_fifo;
 
@@ -1024,12 +1036,12 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid)
 {
-       int tx_fifo_id, txq_id, sta_id, ssn = -1;
+       int tx_fifo_id, txq_id, sta_id, ssn;
        struct iwl_tid_data *tid_data;
        int write_ptr, read_ptr;
        unsigned long flags;
 
-       tx_fifo_id = get_fifo_from_tid(tid);
+       tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
        if (unlikely(tx_fifo_id < 0))
                return tx_fifo_id;
 
@@ -1042,21 +1054,26 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       if (priv->stations[sta_id].tid[tid].agg.state ==
-                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
-               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-               spin_unlock_irqrestore(&priv->sta_lock, flags);
-               return 0;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
-               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
-
        tid_data = &priv->stations[sta_id].tid[tid];
        ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
        txq_id = tid_data->agg.txq_id;
+
+       switch (priv->stations[sta_id].tid[tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /*
+                * This can happen if the peer stops aggregation
+                * again before we've had a chance to drain the
+                * queue we selected previously, i.e. before the
+                * session was really started completely.
+                */
+               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+               goto turn_off;
+       case IWL_AGG_ON:
+               break;
+       default:
+               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
+       }
+
        write_ptr = priv->txq[txq_id].q.write_ptr;
        read_ptr = priv->txq[txq_id].q.read_ptr;
 
@@ -1070,6 +1087,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
        }
 
        IWL_DEBUG_HT(priv, "HW queue is empty\n");
+ turn_off:
        priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
 
        /* do not restore/save irqs */
@@ -1098,6 +1116,9 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        struct iwl_queue *q = &priv->txq[txq_id].q;
        u8 *addr = priv->stations[sta_id].sta.sta.addr;
        struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+       struct iwl_rxon_context *ctx;
+
+       ctx = &priv->contexts[priv->stations[sta_id].ctxid];
 
        lockdep_assert_held(&priv->sta_lock);
 
@@ -1108,12 +1129,12 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
                        u16 ssn = SEQ_TO_SN(tid_data->seq_number);
-                       int tx_fifo = get_fifo_from_tid(tid);
+                       int tx_fifo = get_fifo_from_tid(ctx, tid);
                        IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
                        priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
                                                             ssn, tx_fifo);
                        tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+                       ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1121,7 +1142,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
                if (tid_data->tfds_in_queue == 0) {
                        IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+                       ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
                }
                break;
        }
@@ -1129,14 +1150,14 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
        struct ieee80211_sta *sta;
        struct iwl_station_priv *sta_priv;
 
        rcu_read_lock();
-       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+       sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1);
        if (sta) {
                sta_priv = (void *)sta->drv_priv;
                /* avoid atomic ops if this isn't a client */
@@ -1146,7 +1167,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
        }
        rcu_read_unlock();
 
-       ieee80211_tx_status_irqsafe(priv->hw, skb);
+       ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
 }
 
 int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
@@ -1169,7 +1190,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info->skb);
+               iwlagn_tx_status(priv, tx_info);
 
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
index 6f77441cb65a3f734260e23b1a38a08574d4a668..a7961bf395fcfddb1fd5bc9c4bd7a63260e16424 100644 (file)
@@ -52,6 +52,19 @@ static const s8 iwlagn_default_queue_to_tx_fifo[] = {
        IWL_TX_FIFO_UNUSED,
 };
 
+static const s8 iwlagn_ipan_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWL_TX_FIFO_BK_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWLAGN_CMD_FIFO_NUM,
+};
+
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
         0, COEX_UNASSOC_IDLE_FLAGS},
@@ -329,8 +342,54 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
                                sizeof(coex_cmd), &coex_cmd);
 }
 
+static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       0, 0, 0, 0, 0, 0, 0
+};
+
+static void iwlagn_send_prio_tbl(struct iwl_priv *priv)
+{
+       struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
+
+       memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
+               sizeof(iwlagn_bt_prio_tbl));
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PRIO_TABLE,
+                               sizeof(prio_tbl_cmd), &prio_tbl_cmd))
+               IWL_ERR(priv, "failed to send BT prio tbl command\n");
+}
+
+static void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+{
+       struct iwl_bt_coex_prot_env_cmd env_cmd;
+
+       env_cmd.action = action;
+       env_cmd.type = type;
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+                            sizeof(env_cmd), &env_cmd))
+               IWL_ERR(priv, "failed to send BT env command\n");
+}
+
+
 int iwlagn_alive_notify(struct iwl_priv *priv)
 {
+       const s8 *queues;
        u32 a;
        unsigned long flags;
        int i, chan;
@@ -365,7 +424,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
                           reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
 
        iwl_write_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL,
-               IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
+               IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv));
        iwl_write_prph(priv, IWLAGN_SCD_AGGR_SEL, 0);
 
        /* initiate the queues */
@@ -391,7 +450,13 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
        /* Activate all Tx DMA/FIFO channels */
        priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
-       iwlagn_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+       /* map queues to FIFOs */
+       if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+               queues = iwlagn_ipan_queue_to_tx_fifo;
+       else
+               queues = iwlagn_default_queue_to_tx_fifo;
+
+       iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0);
 
        /* make sure all queue are not stopped */
        memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
@@ -400,11 +465,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
 
        /* reset to 0 to enable all the queue first */
        priv->txq_ctx_active_msk = 0;
-       /* map qos queues to fifos one-to-one */
+
        BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
 
-       for (i = 0; i < ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); i++) {
-               int ac = iwlagn_default_queue_to_tx_fifo[i];
+       for (i = 0; i < 10; i++) {
+               int ac = queues[i];
 
                iwl_txq_ctx_activate(priv, i);
 
@@ -416,6 +482,25 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       if (priv->cfg->advanced_bt_coexist) {
+               /* Configure Bluetooth device coexistence support */
+               /* need to perform this before any calibration */
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->cfg->ops->hcmd->send_bt_config(priv);
+               priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+
+               if (bt_coex_active && priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+                       iwlagn_send_prio_tbl(priv);
+                       iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+                               BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+                       iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+                               BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+               }
+
+       }
+
        iwlagn_send_wimax_coex(priv);
 
        iwlagn_set_Xtal_calib(priv);
index 3ced9ea9c5feba3de87e33057e66683bae5b4cc1..ad0e67f5c0d41d7188ae86f37b78cb5f4263ccda 100644 (file)
@@ -87,6 +87,9 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("iwl4965");
 
+static int iwlagn_ant_coupling;
+static bool iwlagn_bt_ch_announce = 1;
+
 /**
  * iwl_commit_rxon - commit staging_rxon to hardware
  *
@@ -95,21 +98,22 @@ MODULE_ALIAS("iwl4965");
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-int iwl_commit_rxon(struct iwl_priv *priv)
+int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        /* cast away the const for active_rxon in this function */
-       struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+       struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
        int ret;
        bool new_assoc =
-               !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+               !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+       bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
 
        if (!iwl_is_alive(priv))
                return -EBUSY;
 
        /* always get timestamp with Rx frame */
-       priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+       ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
-       ret = iwl_check_rxon_cmd(priv);
+       ret = iwl_check_rxon_cmd(priv, ctx);
        if (ret) {
                IWL_ERR(priv, "Invalid RXON configuration.  Not committing.\n");
                return -EINVAL;
@@ -120,7 +124,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
         * abort any previous channel switch if still in process
         */
        if (priv->switch_rxon.switch_in_progress &&
-           (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
+           (priv->switch_rxon.channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
                      le16_to_cpu(priv->switch_rxon.channel));
                iwl_chswitch_done(priv, false);
@@ -129,15 +133,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
        /* If we don't need to send a full RXON, we can use
         * iwl_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
-       if (!iwl_full_rxon_required(priv)) {
-               ret = iwl_send_rxon_assoc(priv);
+       if (!iwl_full_rxon_required(priv, ctx)) {
+               ret = iwl_send_rxon_assoc(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
                        return ret;
                }
 
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-               iwl_print_rx_config_cmd(priv);
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+               iwl_print_rx_config_cmd(priv, ctx);
                return 0;
        }
 
@@ -145,13 +149,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
         * before we apply the new config */
-       if (iwl_is_associated(priv) && new_assoc) {
+       if (iwl_is_associated_ctx(ctx) && new_assoc) {
                IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                                     sizeof(struct iwl_rxon_cmd),
-                                     &priv->active_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                                      sizeof(struct iwl_rxon_cmd),
+                                      active_rxon);
 
                /* If the mask clearing failed then we set
                 * active_rxon back to what it was previously */
@@ -160,9 +164,9 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
                        return ret;
                }
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
-               ret = iwl_restore_default_wep_keys(priv);
+               iwl_clear_ucode_stations(priv, ctx);
+               iwl_restore_stations(priv, ctx);
+               ret = iwl_restore_default_wep_keys(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
                        return ret;
@@ -174,27 +178,46 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                       "* channel = %d\n"
                       "* bssid = %pM\n",
                       (new_assoc ? "" : "out"),
-                      le16_to_cpu(priv->staging_rxon.channel),
-                      priv->staging_rxon.bssid_addr);
+                      le16_to_cpu(ctx->staging.channel),
+                      ctx->staging.bssid_addr);
+
+       iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+
+       if (!old_assoc) {
+               /*
+                * First of all, before setting associated, we need to
+                * send RXON timing so the device knows about the DTIM
+                * period and other timing values
+                */
+               ret = iwl_send_rxon_timing(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Error setting RXON timing!\n");
+                       return ret;
+               }
+       }
 
-       iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
+       if (priv->cfg->ops->hcmd->set_pan_params) {
+               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+               if (ret)
+                       return ret;
+       }
 
        /* Apply the new configuration
         * RXON unassoc clears the station table in uCode so restoration of
         * stations is needed after it (the RXON command) completes
         */
        if (!new_assoc) {
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                             sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                             sizeof(struct iwl_rxon_cmd), &ctx->staging);
                if (ret) {
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
                IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
-               ret = iwl_restore_default_wep_keys(priv);
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+               iwl_clear_ucode_stations(priv, ctx);
+               iwl_restore_stations(priv, ctx);
+               ret = iwl_restore_default_wep_keys(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
                        return ret;
@@ -206,15 +229,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                /* Apply the new configuration
                 * RXON assoc doesn't clear the station table in uCode,
                 */
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                             sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                             sizeof(struct iwl_rxon_cmd), &ctx->staging);
                if (ret) {
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
        }
-       iwl_print_rx_config_cmd(priv);
+       iwl_print_rx_config_cmd(priv, ctx);
 
        iwl_init_sensitivity(priv);
 
@@ -231,10 +254,14 @@ int iwl_commit_rxon(struct iwl_priv *priv)
 
 void iwl_update_chain_flags(struct iwl_priv *priv)
 {
+       struct iwl_rxon_context *ctx;
 
-       if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
-       iwlcore_commit_rxon(priv);
+       if (priv->cfg->ops->hcmd->set_rxon_chain) {
+               for_each_context(priv, ctx) {
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+                       iwlcore_commit_rxon(priv, ctx);
+               }
+       }
 }
 
 static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -338,6 +365,13 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
         * beacon contents.
         */
 
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
+               return -EINVAL;
+       }
+
        /* Initialize memory */
        tx_beacon_cmd = &frame->u.beacon;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
@@ -350,7 +384,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 
        /* Set up TX command fields */
        tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
-       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+       tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
        tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
        tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
                TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
@@ -360,7 +394,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
                        frame_size);
 
        /* Set up packet rate and flags */
-       rate = iwl_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx);
        priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
                                              priv->hw_params.valid_tx_ant);
        rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
@@ -593,23 +627,84 @@ static void iwl_bg_beacon_update(struct work_struct *work)
                container_of(work, struct iwl_priv, beacon_update);
        struct sk_buff *beacon;
 
-       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       mutex_lock(&priv->mutex);
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "updating beacon w/o beacon context!\n");
+               goto out;
+       }
+
+       if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
+               /*
+                * The ucode will send beacon notifications even in
+                * IBSS mode, but we don't want to process them. But
+                * we need to defer the type check to here due to
+                * requiring locking around the beacon_ctx access.
+                */
+               goto out;
+       }
 
+       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+       beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
        if (!beacon) {
                IWL_ERR(priv, "update beacon failed\n");
-               return;
+               goto out;
        }
 
-       mutex_lock(&priv->mutex);
        /* new beacon skb is allocated every time; dispose previous.*/
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
 
        priv->ibss_beacon = beacon;
-       mutex_unlock(&priv->mutex);
 
        iwl_send_beacon_cmd(priv);
+ out:
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_bt_runtime_config(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_runtime_config);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+       priv->cfg->ops->hcmd->send_bt_config(priv);
+}
+
+static void iwl_bg_bt_full_concurrency(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_full_concurrency);
+       struct iwl_rxon_context *ctx;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       /*
+        * LQ & RXON updated cmds must be sent before BT Config cmd
+        * to avoid 3-wire collisions
+        */
+       mutex_lock(&priv->mutex);
+       for_each_context(priv, ctx) {
+               if (priv->cfg->ops->hcmd->set_rxon_chain)
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+               iwlcore_commit_rxon(priv, ctx);
+       }
+       mutex_unlock(&priv->mutex);
+
+       priv->cfg->ops->hcmd->send_bt_config(priv);
 }
 
 /**
@@ -781,8 +876,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 
        priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
 
-       if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-           (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
                queue_work(priv->workqueue, &priv->beacon_update);
 }
 
@@ -1653,6 +1747,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
 struct iwlagn_ucode_capabilities {
        u32 max_probe_length;
        u32 standard_phy_calibration_size;
+       bool pan;
 };
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
@@ -1890,6 +1985,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
                        capa->max_probe_length =
                                        le32_to_cpup((__le32 *)tlv_data);
                        break;
+               case IWL_UCODE_TLV_PAN:
+                       if (tlv_len)
+                               goto invalid_tlv_len;
+                       capa->pan = true;
+                       break;
                case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
                        if (tlv_len != sizeof(u32))
                                goto invalid_tlv_len;
@@ -2165,6 +2265,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
        priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 
+       if (ucode_capa.pan) {
+               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+       } else
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
@@ -2563,6 +2669,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                return pos;
        }
 
+       /* enable/disable bt channel announcement */
+       priv->bt_ch_announce = iwlagn_bt_ch_announce;
+
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log)
                size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
@@ -2663,6 +2772,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
 static void iwl_alive_start(struct iwl_priv *priv)
 {
        int ret = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
@@ -2711,27 +2821,31 @@ static void iwl_alive_start(struct iwl_priv *priv)
        if (priv->cfg->ops->hcmd->set_tx_ant)
                priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant);
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated_ctx(ctx)) {
                struct iwl_rxon_cmd *active_rxon =
-                               (struct iwl_rxon_cmd *)&priv->active_rxon;
+                               (struct iwl_rxon_cmd *)&ctx->active;
                /* apply any changes in staging */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
+               struct iwl_rxon_context *tmp;
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, NULL);
+               for_each_context(priv, tmp)
+                       iwl_connection_init_rx_config(priv, tmp);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
-       /* Configure Bluetooth device coexistence support */
-       priv->cfg->ops->hcmd->send_bt_config(priv);
+       if (!priv->cfg->advanced_bt_coexist) {
+               /* Configure Bluetooth device coexistence support */
+               priv->cfg->ops->hcmd->send_bt_config(priv);
+       }
 
        iwl_reset_run_time_calib(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        /* At this point, the NIC is initialized and operational */
        iwl_rf_kill_ct_config(priv);
@@ -2764,10 +2878,22 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_ucode_stations(priv);
-       iwl_dealloc_bcast_station(priv);
+       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+        * to prevent rearm timer */
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
+
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
 
+       /* reset BT coex data */
+       priv->bt_status = 0;
+       priv->bt_traffic_load = priv->cfg->bt_init_traffic_load;
+       priv->bt_sco_active = false;
+       priv->bt_full_concurrent = false;
+       priv->bt_ci_compliance = 0;
+
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
 
@@ -2900,6 +3026,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 
 static int __iwl_up(struct iwl_priv *priv)
 {
+       struct iwl_rxon_context *ctx;
        int i;
        int ret;
 
@@ -2913,9 +3040,13 @@ static int __iwl_up(struct iwl_priv *priv)
                return -EIO;
        }
 
-       ret = iwl_alloc_bcast_station(priv, true);
-       if (ret)
-               return ret;
+       for_each_context(priv, ctx) {
+               ret = iwl_alloc_bcast_station(priv, ctx, true);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
 
        iwl_prepare_card_hw(priv);
 
@@ -2940,6 +3071,12 @@ static int __iwl_up(struct iwl_priv *priv)
 
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
+       /* must be initialised before iwl_hw_nic_init */
+       if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+               priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+       else
+               priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+
        ret = iwlagn_hw_nic_init(priv);
        if (ret) {
                IWL_ERR(priv, "Unable to init nic\n");
@@ -3070,11 +3207,42 @@ static void iwl_bg_restart(struct work_struct *data)
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               struct iwl_rxon_context *ctx;
+               bool bt_sco, bt_full_concurrent;
+               u8 bt_ci_compliance;
+               u8 bt_load;
+               u8 bt_status;
+
                mutex_lock(&priv->mutex);
-               priv->vif = NULL;
+               for_each_context(priv, ctx)
+                       ctx->vif = NULL;
                priv->is_open = 0;
+
+               /*
+                * __iwl_down() will clear the BT status variables,
+                * which is correct, but when we restart we really
+                * want to keep them so restore them afterwards.
+                *
+                * The restart process will later pick them up and
+                * re-configure the hw when we reconfigure the BT
+                * command.
+                */
+               bt_sco = priv->bt_sco_active;
+               bt_full_concurrent = priv->bt_full_concurrent;
+               bt_ci_compliance = priv->bt_ci_compliance;
+               bt_load = priv->bt_traffic_load;
+               bt_status = priv->bt_status;
+
+               __iwl_down(priv);
+
+               priv->bt_sco_active = bt_sco;
+               priv->bt_full_concurrent = bt_full_concurrent;
+               priv->bt_ci_compliance = bt_ci_compliance;
+               priv->bt_traffic_load = bt_load;
+               priv->bt_status = bt_status;
+
                mutex_unlock(&priv->mutex);
-               iwl_down(priv);
+               iwl_cancel_deferred_work(priv);
                ieee80211_restart_hw(priv->hw);
        } else {
                iwl_down(priv);
@@ -3105,12 +3273,15 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
 
 void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx;
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
 
        if (!vif || !priv->is_open)
                return;
 
+       ctx = iwl_rxon_ctx_from_vif(vif);
+
        if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
@@ -3123,42 +3294,42 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
-       ret = iwl_send_rxon_timing(priv, vif);
+       ret = iwl_send_rxon_timing(priv, ctx);
        if (ret)
-               IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+               IWL_WARN(priv, "RXON timing - "
                            "Attempting to continue.\n");
 
-       priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
        iwl_set_rxon_ht(priv, &priv->current_ht_config);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
        if (vif->bss_conf.use_short_preamble)
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                if (vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
 
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, ctx->active.bssid_addr);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -3201,11 +3372,14 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
        hw->rate_control_algorithm = "iwl-agn-rs";
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
        if (!priv->cfg->broken_powersave)
@@ -3219,9 +3393,10 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
        hw->sta_data_size = sizeof(struct iwl_station_priv);
        hw->vif_data_size = sizeof(struct iwl_vif_priv);
 
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3349,22 +3524,25 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        int ret = 0;
 
+       lockdep_assert_held(&priv->mutex);
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_associated_ctx(ctx)) {
 
                /* RXON - unassoc (to set timing command) */
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
 
                /* RXON Timing */
-               ret = iwl_send_rxon_timing(priv, vif);
+               ret = iwl_send_rxon_timing(priv, ctx);
                if (ret)
-                       IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+                       IWL_WARN(priv, "RXON timing failed - "
                                        "Attempting to continue.\n");
 
                /* AP has all antennas */
@@ -3372,28 +3550,30 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        priv->hw_params.valid_rx_ant;
                iwl_set_rxon_ht(priv, &priv->current_ht_config);
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-               priv->staging_rxon.assoc_id = 0;
+               ctx->staging.assoc_id = 0;
 
                if (vif->bss_conf.use_short_preamble)
-                       priv->staging_rxon.flags |=
+                       ctx->staging.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &=
+                       ctx->staging.flags &=
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-               if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+               if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                        if (vif->bss_conf.use_short_slot)
-                               priv->staging_rxon.flags |=
+                               ctx->staging.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
-                               priv->staging_rxon.flags &=
+                               ctx->staging.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
+               /* need to send beacon cmd before committing assoc RXON! */
+               iwl_send_beacon_cmd(priv);
                /* restore RXON assoc */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
        }
        iwl_send_beacon_cmd(priv);
 
@@ -3410,9 +3590,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
 {
 
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       iwl_update_tkip_key(priv, keyconf, sta,
+       iwl_update_tkip_key(priv, vif_priv->ctx, keyconf, sta,
                            iv32, phase1key);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3424,6 +3606,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
        int ret;
        u8 sta_id;
        bool is_default_wep_key = false;
@@ -3435,7 +3619,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       sta_id = iwl_sta_id_or_broadcast(priv, sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta);
        if (sta_id == IWL_INVALID_STATION)
                return -EINVAL;
 
@@ -3452,7 +3636,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
             key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
            !sta) {
                if (cmd == SET_KEY)
-                       is_default_wep_key = !priv->key_mapping_key;
+                       is_default_wep_key = !ctx->key_mapping_keys;
                else
                        is_default_wep_key =
                                        (key->hw_key_idx == HW_KEY_DEFAULT);
@@ -3461,17 +3645,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        switch (cmd) {
        case SET_KEY:
                if (is_default_wep_key)
-                       ret = iwl_set_default_wep_key(priv, key);
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
                else
-                       ret = iwl_set_dynamic_key(priv, key, sta_id);
+                       ret = iwl_set_dynamic_key(priv, vif_priv->ctx,
+                                                 key, sta_id);
 
                IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
                break;
        case DISABLE_KEY:
                if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, key);
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
                else
-                       ret = iwl_remove_dynamic_key(priv, key, sta_id);
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta_id);
 
                IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
                break;
@@ -3540,8 +3725,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 
                        sta_priv->lq_sta.lq.general_params.flags &=
                                ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
-                               CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
                }
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -3556,8 +3741,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 
                        sta_priv->lq_sta.lq.general_params.flags |=
                                LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
-                               CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
                }
                ret = 0;
                break;
@@ -3603,6 +3788,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
        bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        int ret;
        u8 sta_id;
@@ -3618,8 +3804,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
        if (vif->type == NL80211_IFTYPE_AP)
                sta_priv->client = true;
 
-       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
-                                    &sta_id);
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
@@ -3647,6 +3833,15 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
        struct ieee80211_conf *conf = &hw->conf;
        struct ieee80211_channel *channel = ch_switch->channel;
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u16 ch;
        unsigned long flags = 0;
 
@@ -3659,7 +3854,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
            test_bit(STATUS_SCANNING, &priv->status))
                goto out_exit;
 
-       if (!iwl_is_associated(priv))
+       if (!iwl_is_associated_ctx(ctx))
                goto out_exit;
 
        /* channel switch in progress */
@@ -3670,7 +3865,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
        if (priv->cfg->ops->lib->set_channel_switch) {
 
                ch = channel->hw_value;
-               if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+               if (le16_to_cpu(ctx->active.channel) != ch) {
                        ch_info = iwl_get_channel_info(priv,
                                                       channel->band,
                                                       ch);
@@ -3683,31 +3878,31 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
                        priv->current_ht_config.smps = conf->smps_mode;
 
                        /* Configure HT40 channels */
-                       ht_conf->is_ht = conf_is_ht(conf);
-                       if (ht_conf->is_ht) {
+                       ctx->ht.enabled = conf_is_ht(conf);
+                       if (ctx->ht.enabled) {
                                if (conf_is_ht40_minus(conf)) {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                                       ht_conf->is_40mhz = true;
+                                       ctx->ht.is_40mhz = true;
                                } else if (conf_is_ht40_plus(conf)) {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                                       ht_conf->is_40mhz = true;
+                                       ctx->ht.is_40mhz = true;
                                } else {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                                       ht_conf->is_40mhz = false;
+                                       ctx->ht.is_40mhz = false;
                                }
                        } else
-                               ht_conf->is_40mhz = false;
+                               ctx->ht.is_40mhz = false;
 
-                       if (le16_to_cpu(priv->staging_rxon.channel) != ch)
-                               priv->staging_rxon.flags = 0;
+                       if ((le16_to_cpu(ctx->staging.channel) != ch))
+                               ctx->staging.flags = 0;
 
-                       iwl_set_rxon_channel(priv, channel);
+                       iwl_set_rxon_channel(priv, channel, ctx);
                        iwl_set_rxon_ht(priv, ht_conf);
-                       iwl_set_flags_for_band(priv, channel->band,
-                                              priv->vif);
+                       iwl_set_flags_for_band(priv, ctx, channel->band,
+                                              ctx->vif);
                        spin_unlock_irqrestore(&priv->lock, flags);
 
                        iwl_set_rate(priv);
@@ -3724,7 +3919,7 @@ out:
        mutex_unlock(&priv->mutex);
 out_exit:
        if (!priv->switch_rxon.switch_in_progress)
-               ieee80211_chswitch_done(priv->vif, false);
+               ieee80211_chswitch_done(ctx->vif, false);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -3735,6 +3930,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
 
 #define CHK(test, flag)        do { \
        if (*total_flags & (test))              \
@@ -3754,10 +3950,11 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       priv->staging_rxon.filter_flags &= ~filter_nand;
-       priv->staging_rxon.filter_flags |= filter_or;
-
-       iwlcore_commit_rxon(priv);
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+               iwlcore_commit_rxon(priv, ctx);
+       }
 
        mutex_unlock(&priv->mutex);
 
@@ -3826,6 +4023,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
        INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
        INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
@@ -3868,10 +4067,10 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->run_time_calib_work);
        cancel_work_sync(&priv->beacon_update);
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
        del_timer_sync(&priv->statistics_periodic);
        del_timer_sync(&priv->ucode_trace);
-       if (priv->cfg->ops->lib->recover_from_tx_stall)
-               del_timer_sync(&priv->monitor_recover);
 }
 
 static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3926,10 +4125,22 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv,
+                                       &priv->contexts[IWL_RXON_CTX_BSS]);
 
        iwl_init_scan_params(priv);
 
+       /* init bt coex */
+       if (priv->cfg->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;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+               priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF;
+       }
+
        /* Set the tx_power_user_lmt to the lowest power level
         * this value will get overwritten by channel max power avg
         * from eeprom */
@@ -4013,9 +4224,31 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
        return priv->cfg->ops->lib->set_hw_params(priv);
 }
 
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static const u8 iwlagn_bss_ac_to_queue[] = {
+       0, 1, 2, 3,
+};
+
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_BK_IPAN,
+};
+
+static const u8 iwlagn_pan_ac_to_queue[] = {
+       7, 6, 5, 4,
+};
+
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int err = 0;
+       int err = 0, i;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -4043,6 +4276,51 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        priv = hw->priv;
        /* At this point both hw and priv are allocated. */
 
+       /*
+        * The default context is always valid,
+        * more may be discovered when firmware
+        * is loaded.
+        */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
+       priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
+       priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+               BIT(NL80211_IFTYPE_ADHOC);
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION);
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = REPLY_WIPAN_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = REPLY_WIPAN_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+       priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+       priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+       priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
+       priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
+       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
+       priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+       priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+       priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+       priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
        IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
@@ -4050,6 +4328,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        priv->pci_dev = pdev;
        priv->inta_mask = CSR_INI_SET_MASK;
 
+       /* is antenna coupling more than 35dB ? */
+       priv->bt_ant_couple_ok =
+               (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
+               true : false;
+
+       /* enable/disable bt channel announcement */
+       priv->bt_ch_announce = iwlagn_bt_ch_announce;
+
        if (iwl_alloc_traffic_mem(priv))
                IWL_ERR(priv, "Not enough memory to generate traffic log\n");
 
@@ -4583,3 +4869,11 @@ module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
                   S_IRUGO);
 MODULE_PARM_DESC(ucode_alternative,
                 "specify ucode alternative to use from ucode file");
+
+module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO);
+MODULE_PARM_DESC(antenna_coupling,
+                "specify antenna coupling in dB (defualt: 0 dB)");
+
+module_param_named(bt_ch_announce, iwlagn_bt_ch_announce, bool, S_IRUGO);
+MODULE_PARM_DESC(bt_ch_announce,
+                "Enable BT channel announcement mode (default: enable)");
index cc6464dc72e592bd57302423b84784f0b4b63d8d..7c542a8c8f8131e2ce717a513d04251e640c27a1 100644 (file)
@@ -95,6 +95,7 @@ extern struct iwl_cfg iwl1000_bg_cfg;
 
 extern struct iwl_mod_params iwlagn_mod_params;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
+extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
 extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
 
 int iwl_reset_ict(struct iwl_priv *priv);
@@ -223,7 +224,16 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
                               struct ieee80211_vif *vif, bool add);
 
 /* hcmd */
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx);
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 
+/* bt coex */
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
+void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb);
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
+
 #endif /* __iwl_agn_h__ */
index 4083e4430827abbceab63b39faf29d15dc5b55fe..3e4ba31b5d59ad0a666ad185d3e4c058e00383a8 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-commands.h) only for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
+ * Please use iwl-xxxx-hw.h for hardware-related definitions.
  * Please use iwl-dev.h for driver implementation definitions.
  */
 
@@ -173,6 +173,23 @@ enum {
        REPLY_RX_MPDU_CMD = 0xc1,
        REPLY_RX = 0xc3,
        REPLY_COMPRESSED_BA = 0xc5,
+
+       /* BT Coex */
+       REPLY_BT_COEX_PRIO_TABLE = 0xcc,
+       REPLY_BT_COEX_PROT_ENV = 0xcd,
+       REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
+       REPLY_BT_COEX_SCO = 0xcf,
+
+       /* PAN commands */
+       REPLY_WIPAN_PARAMS = 0xb2,
+       REPLY_WIPAN_RXON = 0xb3,        /* use REPLY_RXON structure */
+       REPLY_WIPAN_RXON_TIMING = 0xb4, /* use REPLY_RXON_TIMING structure */
+       REPLY_WIPAN_RXON_ASSOC = 0xb6,  /* use REPLY_RXON_ASSOC structure */
+       REPLY_WIPAN_QOS_PARAM = 0xb7,   /* use REPLY_QOS_PARAM structure */
+       REPLY_WIPAN_WEPKEY = 0xb8,      /* use REPLY_WEPKEY structure */
+       REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
+       REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
+
        REPLY_MAX = 0xff
 };
 
@@ -600,6 +617,9 @@ enum {
        RXON_DEV_TYPE_ESS = 3,
        RXON_DEV_TYPE_IBSS = 4,
        RXON_DEV_TYPE_SNIFFER = 6,
+       RXON_DEV_TYPE_CP = 7,
+       RXON_DEV_TYPE_2STA = 8,
+       RXON_DEV_TYPE_P2P = 9,
 };
 
 
@@ -816,7 +836,8 @@ struct iwl_rxon_time_cmd {
        __le16 atim_window;
        __le32 beacon_init_val;
        __le16 listen_interval;
-       __le16 reserved;
+       u8 dtim_period;
+       u8 delta_cp_bss_tbtts;
 } __packed;
 
 /*
@@ -953,11 +974,13 @@ struct iwl_qosparam_cmd {
 
 /* Special, dedicated locations within device's station table */
 #define        IWL_AP_ID               0
+#define        IWL_AP_ID_PAN           1
 #define        IWL_STA_ID              2
 #define        IWL3945_BROADCAST_ID    24
 #define IWL3945_STATION_COUNT  25
 #define IWL4965_BROADCAST_ID   31
 #define        IWL4965_STATION_COUNT   32
+#define IWLAGN_PAN_BCAST_ID    14
 #define IWLAGN_BROADCAST_ID    15
 #define        IWLAGN_STATION_COUNT    16
 
@@ -966,6 +989,7 @@ struct iwl_qosparam_cmd {
 
 #define STA_FLG_TX_RATE_MSK            cpu_to_le32(1 << 2)
 #define STA_FLG_PWR_SAVE_MSK           cpu_to_le32(1 << 8)
+#define STA_FLG_PAN_STATION            cpu_to_le32(1 << 13)
 #define STA_FLG_RTS_MIMO_PROT_MSK      cpu_to_le32(1 << 17)
 #define STA_FLG_AGG_MPDU_8US_MSK       cpu_to_le32(1 << 18)
 #define STA_FLG_MAX_AGG_SIZE_POS       (19)
@@ -994,6 +1018,7 @@ struct iwl_qosparam_cmd {
 #define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
 #define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
 #define STA_KEY_MAX_NUM                8
+#define STA_KEY_MAX_NUM_PAN    16
 
 /* Flags indicate whether to modify vs. don't change various station params */
 #define        STA_MODIFY_KEY_MASK             0x01
@@ -1056,7 +1081,8 @@ struct sta_id_modify {
  *
  * The device contains an internal table of per-station information,
  * with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * initial Tx attempt and any retries (agn devices uses
+ * REPLY_TX_LINK_QUALITY_CMD,
  * 3945 uses REPLY_RATE_SCALE to set up rate tables).
  *
  * REPLY_ADD_STA sets up the table entry for one station, either creating
@@ -1427,12 +1453,12 @@ struct iwl_rx_mpdu_res_start {
  * uCode handles all timing and protocol related to control frames
  * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
  * handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA (4965).
+ * REPLY_COMPRESSED_BA.
  *
  * uCode handles retrying Tx when an ACK is expected but not received.
  * This includes trying lower data rates than the one requested in the Tx
  * command, as set up by the REPLY_RATE_SCALE (for 3945) or
- * REPLY_TX_LINK_QUALITY_CMD (4965).
+ * REPLY_TX_LINK_QUALITY_CMD (agn).
  *
  * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
  * This command must be executed after every RXON command, before Tx can occur.
@@ -1468,7 +1494,7 @@ struct iwl_rx_mpdu_res_start {
  * Set this for unicast frames, but not broadcast/multicast. */
 #define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
 
-/* For 4965:
+/* For agn devices:
  * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
  *    Tx command's initial_rate_index indicates first rate to try;
  *    uCode walks through table for additional Tx attempts.
@@ -1487,7 +1513,7 @@ struct iwl_rx_mpdu_res_start {
  */
 #define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
 
-/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+/* Tx antenna selection field; used only for 3945, reserved (0) for agn devices.
  * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
 #define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
 #define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
@@ -1870,9 +1896,10 @@ enum {
  *     frame in this new agg block failed in previous agg block(s).
  *
  *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
- *     block-ack has not been received by the time the 4965 records this status.
+ *     block-ack has not been received by the time the agn device records
+ *     this status.
  *     This status relates to reasons the tx might have been blocked or aborted
- *     within the sending station (this 4965), rather than whether it was
+ *     within the sending station (this agn device), rather than whether it was
  *     received successfully by the destination station.
  */
 struct agg_tx_status {
@@ -2140,14 +2167,16 @@ struct iwl_link_qual_agg_params {
 /*
  * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
  *
- * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ * For agn devices only; 3945 uses REPLY_RATE_SCALE.
  *
- * Each station in the 4965's internal station table has its own table of 16
+ * Each station in the agn device's internal station table has its own table
+ * of 16
  * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
  * an ACK is not received.  This command replaces the entire table for
  * one station.
  *
- * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
+ * NOTE:  Station must already be in agn device's station table.
+ *       Use REPLY_ADD_STA.
  *
  * The rate scaling procedures described below work well.  Of course, other
  * procedures are possible, and may work better for particular environments.
@@ -2184,12 +2213,12 @@ struct iwl_link_qual_agg_params {
  *
  * ACCUMULATING HISTORY
  *
- * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
- * two sets of frame Tx success history:  One for the current/active modulation
- * mode, and one for a speculative/search mode that is being attempted.  If the
- * speculative mode turns out to be more effective (i.e. actual transfer
- * rate is better), then the driver continues to use the speculative mode
- * as the new current active mode.
+ * The rate scaling algorithm for agn devices, as implemented in Linux driver,
+ * uses two sets of frame Tx success history:  One for the current/active
+ * modulation mode, and one for a speculative/search mode that is being
+ * attempted. If the speculative mode turns out to be more effective (i.e.
+ * actual transfer rate is better), then the driver continues to use the
+ * speculative mode as the new current active mode.
  *
  * Each history set contains, separately for each possible rate, data for a
  * sliding window of the 62 most recent tx attempts at that rate.  The data
@@ -2200,12 +2229,12 @@ struct iwl_link_qual_agg_params {
  * The driver uses the bit map to remove successes from the success sum, as
  * the oldest tx attempts fall out of the window.
  *
- * When the 4965 makes multiple tx attempts for a given frame, each attempt
- * might be at a different rate, and have different modulation characteristics
- * (e.g. antenna, fat channel, short guard interval), as set up in the rate
- * scaling table in the Link Quality command.  The driver must determine
- * which rate table entry was used for each tx attempt, to determine which
- * rate-specific history to update, and record only those attempts that
+ * When the agn device makes multiple tx attempts for a given frame, each
+ * attempt might be at a different rate, and have different modulation
+ * characteristics (e.g. antenna, fat channel, short guard interval), as set
+ * up in the rate scaling table in the Link Quality command.  The driver must
+ * determine which rate table entry was used for each tx attempt, to determine
+ * which rate-specific history to update, and record only those attempts that
  * match the modulation characteristics of the history set.
  *
  * When using block-ack (aggregation), all frames are transmitted at the same
@@ -2335,7 +2364,7 @@ struct iwl_link_quality_cmd {
        /*
         * Rate info; when using rate-scaling, Tx command's initial_rate_index
         * specifies 1st Tx rate attempted, via index into this table.
-        * 4965 works its way through table when retrying Tx.
+        * agn devices works its way through table when retrying Tx.
         */
        struct {
                __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
@@ -2368,10 +2397,26 @@ struct iwl_link_quality_cmd {
 #define BT_MAX_KILL_DEF (0x5)
 #define BT_MAX_KILL_MAX (0xFF)
 
+#define BT_DURATION_LIMIT_DEF  625
+#define BT_DURATION_LIMIT_MAX  1250
+#define BT_DURATION_LIMIT_MIN  625
+
+#define BT_ON_THRESHOLD_DEF    4
+#define BT_ON_THRESHOLD_MAX    1000
+#define BT_ON_THRESHOLD_MIN    1
+
+#define BT_FRAG_THRESHOLD_DEF  0
+#define BT_FRAG_THRESHOLD_MAX  0
+#define BT_FRAG_THRESHOLD_MIN  0
+
+#define BT_AGG_THRESHOLD_DEF   0
+#define BT_AGG_THRESHOLD_MAX   0
+#define BT_AGG_THRESHOLD_MIN   0
+
 /*
  * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
  *
- * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * 3945 and agn devices support hardware handshake with Bluetooth device on
  * same platform.  Bluetooth device alerts wireless device when it will Tx;
  * wireless device can delay or kill its own Tx to accommodate.
  */
@@ -2384,6 +2429,74 @@ struct iwl_bt_cmd {
        __le32 kill_cts_mask;
 } __packed;
 
+#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION      BIT(0)
+
+#define IWLAGN_BT_FLAG_COEX_MODE_MASK          (BIT(3)|BIT(4)|BIT(5))
+#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT         3
+#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED      0
+#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W     1
+#define IWLAGN_BT_FLAG_COEX_MODE_3W            2
+#define IWLAGN_BT_FLAG_COEX_MODE_4W            3
+
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT   BIT(6)
+#define IWLAGN_BT_FLAG_NOCOEX_NOTIF    BIT(7)
+
+#define IWLAGN_BT_PRIO_BOOST_MAX       0xFF
+#define IWLAGN_BT_PRIO_BOOST_MIN       0x00
+#define IWLAGN_BT_PRIO_BOOST_DEFAULT   0xF0
+
+#define IWLAGN_BT_MAX_KILL_DEFAULT     5
+
+#define IWLAGN_BT3_T7_DEFAULT          1
+
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT        cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT        cpu_to_le32(0xffffffff)
+
+#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
+
+#define IWLAGN_BT3_T2_DEFAULT          0xc
+
+#define IWLAGN_BT_VALID_ENABLE_FLAGS   cpu_to_le16(BIT(0))
+#define IWLAGN_BT_VALID_BOOST          cpu_to_le16(BIT(1))
+#define IWLAGN_BT_VALID_MAX_KILL       cpu_to_le16(BIT(2))
+#define IWLAGN_BT_VALID_3W_TIMERS      cpu_to_le16(BIT(3))
+#define IWLAGN_BT_VALID_KILL_ACK_MASK  cpu_to_le16(BIT(4))
+#define IWLAGN_BT_VALID_KILL_CTS_MASK  cpu_to_le16(BIT(5))
+#define IWLAGN_BT_VALID_BT4_TIMES      cpu_to_le16(BIT(6))
+#define IWLAGN_BT_VALID_3W_LUT         cpu_to_le16(BIT(7))
+
+#define IWLAGN_BT_ALL_VALID_MSK                (IWLAGN_BT_VALID_ENABLE_FLAGS | \
+                                       IWLAGN_BT_VALID_BOOST | \
+                                       IWLAGN_BT_VALID_MAX_KILL | \
+                                       IWLAGN_BT_VALID_3W_TIMERS | \
+                                       IWLAGN_BT_VALID_KILL_ACK_MASK | \
+                                       IWLAGN_BT_VALID_KILL_CTS_MASK | \
+                                       IWLAGN_BT_VALID_BT4_TIMES | \
+                                       IWLAGN_BT_VALID_3W_LUT)
+
+struct iwlagn_bt_cmd {
+       u8 flags;
+       u8 ledtime; /* unused */
+       u8 max_kill;
+       u8 bt3_timer_t7_value;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       u8 bt3_prio_sample_time;
+       u8 bt3_timer_t2_value;
+       __le16 bt4_reaction_time; /* unused */
+       __le32 bt3_lookup_table[12];
+       __le16 bt4_decision_time; /* unused */
+       __le16 valid;
+       u8 prio_boost;
+       u8 reserved[3];
+};
+
+#define IWLAGN_BT_SCO_ACTIVE   cpu_to_le32(BIT(0))
+
+struct iwlagn_bt_sco_cmd {
+       __le32 flags;
+};
+
 /******************************************************************************
  * (6)
  * Spectrum Management (802.11h) Commands, Responses, Notifications:
@@ -2572,7 +2685,7 @@ struct iwl_powertable_cmd {
 
 /*
  * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * 3945 and 4965 identical.
+ * all devices identical.
  */
 struct iwl_sleep_notification {
        u8 pm_sleep_mode;
@@ -2583,7 +2696,7 @@ struct iwl_sleep_notification {
        __le32 bcon_timer;
 } __packed;
 
-/* Sleep states.  3945 and 4965 identical. */
+/* Sleep states.  all devices identical. */
 enum {
        IWL_PM_NO_SLEEP = 0,
        IWL_PM_SLP_MAC = 1,
@@ -2892,6 +3005,12 @@ struct iwl_scanstart_notification {
 #define  SCAN_OWNER_STATUS 0x1;
 #define  MEASURE_OWNER_STATUS 0x2;
 
+#define IWL_PROBE_STATUS_OK            0
+#define IWL_PROBE_STATUS_TX_FAILED     BIT(0)
+/* error statuses combined with TX_FAILED */
+#define IWL_PROBE_STATUS_FAIL_TTL      BIT(1)
+#define IWL_PROBE_STATUS_FAIL_BT       BIT(2)
+
 #define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
 /*
  * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
@@ -2899,7 +3018,8 @@ struct iwl_scanstart_notification {
 struct iwl_scanresults_notification {
        u8 channel;
        u8 band;
-       u8 reserved[2];
+       u8 probe_status;
+       u8 num_probe_not_sent; /* not enough time to send */
        __le32 tsf_low;
        __le32 tsf_high;
        __le32 statistics[NUMBER_OF_STATISTICS];
@@ -2911,7 +3031,7 @@ struct iwl_scanresults_notification {
 struct iwl_scancomplete_notification {
        u8 scanned_channels;
        u8 status;
-       u8 reserved;
+       u8 bt_status;   /* BT On/Off status */
        u8 last_channel;
        __le32 tsf_low;
        __le32 tsf_high;
@@ -3270,7 +3390,7 @@ struct statistics_general_bt {
 
 /*
  * REPLY_STATISTICS_CMD = 0x9c,
- * 3945 and 4965 identical.
+ * all devices identical.
  *
  * This command triggers an immediate response containing uCode statistics.
  * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
@@ -3608,7 +3728,7 @@ struct iwl_enhance_sensitivity_cmd {
 /**
  * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
  *
- * This command sets the relative gains of 4965's 3 radio receiver chains.
+ * This command sets the relative gains of agn device's 3 radio receiver chains.
  *
  * After the first association, driver should accumulate signal and noise
  * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
@@ -3964,6 +4084,201 @@ struct iwl_coex_event_resp {
 } __packed;
 
 
+/******************************************************************************
+ * Bluetooth Coexistence commands
+ *
+ *****************************************************************************/
+
+/*
+ * BT Status notification
+ * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
+ */
+enum iwl_bt_coex_profile_traffic_load {
+       IWL_BT_COEX_TRAFFIC_LOAD_NONE =         0,
+       IWL_BT_COEX_TRAFFIC_LOAD_LOW =          1,
+       IWL_BT_COEX_TRAFFIC_LOAD_HIGH =         2,
+       IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =   3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+#define BT_UART_MSG_FRAME1MSGTYPE_POS          (0)
+#define BT_UART_MSG_FRAME1MSGTYPE_MSK          \
+               (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
+#define BT_UART_MSG_FRAME1SSN_POS              (3)
+#define BT_UART_MSG_FRAME1SSN_MSK              \
+               (0x3 << BT_UART_MSG_FRAME1SSN_POS)
+#define BT_UART_MSG_FRAME1UPDATEREQ_POS                (5)
+#define BT_UART_MSG_FRAME1UPDATEREQ_MSK                \
+               (0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
+#define BT_UART_MSG_FRAME1RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME1RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
+
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS  (0)
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK  \
+               (0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS      (2)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK      \
+               (0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
+#define BT_UART_MSG_FRAME2CHLSEQN_POS          (4)
+#define BT_UART_MSG_FRAME2CHLSEQN_MSK          \
+               (0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
+#define BT_UART_MSG_FRAME2INBAND_POS           (5)
+#define BT_UART_MSG_FRAME2INBAND_MSK           \
+               (0x1 << BT_UART_MSG_FRAME2INBAND_POS)
+#define BT_UART_MSG_FRAME2RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME2RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_FRAME3SCOESCO_POS          (0)
+#define BT_UART_MSG_FRAME3SCOESCO_MSK          \
+               (0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
+#define BT_UART_MSG_FRAME3SNIFF_POS            (1)
+#define BT_UART_MSG_FRAME3SNIFF_MSK            \
+               (0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
+#define BT_UART_MSG_FRAME3A2DP_POS             (2)
+#define BT_UART_MSG_FRAME3A2DP_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3A2DP_POS)
+#define BT_UART_MSG_FRAME3ACL_POS              (3)
+#define BT_UART_MSG_FRAME3ACL_MSK              \
+               (0x1 << BT_UART_MSG_FRAME3ACL_POS)
+#define BT_UART_MSG_FRAME3MASTER_POS           (4)
+#define BT_UART_MSG_FRAME3MASTER_MSK           \
+               (0x1 << BT_UART_MSG_FRAME3MASTER_POS)
+#define BT_UART_MSG_FRAME3OBEX_POS             (5)
+#define BT_UART_MSG_FRAME3OBEX_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3OBEX_POS)
+#define BT_UART_MSG_FRAME3RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME3RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_FRAME4IDLEDURATION_POS     (0)
+#define BT_UART_MSG_FRAME4IDLEDURATION_MSK     \
+               (0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
+#define BT_UART_MSG_FRAME4RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME4RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_FRAME5TXACTIVITY_POS       (0)
+#define BT_UART_MSG_FRAME5TXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5RXACTIVITY_POS       (2)
+#define BT_UART_MSG_FRAME5RXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS   (4)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK   \
+               (0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
+#define BT_UART_MSG_FRAME5RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME5RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS    (0)
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK    \
+               (0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_POS     (5)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK     \
+               (0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
+#define BT_UART_MSG_FRAME6RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME6RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS    (0)
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK    \
+               (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS        (3)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK        \
+               (0x3 << BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS)
+#define BT_UART_MSG_FRAME7CONNECTABLE_POS      (5)
+#define BT_UART_MSG_FRAME7CONNECTABLE_MSK      \
+               (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
+#define BT_UART_MSG_FRAME7RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME7RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
+
+
+struct iwl_bt_uart_msg {
+       u8 header;
+       u8 frame1;
+       u8 frame2;
+       u8 frame3;
+       u8 frame4;
+       u8 frame5;
+       u8 frame6;
+       u8 frame7;
+} __attribute__((packed));
+
+struct iwl_bt_coex_profile_notif {
+       struct iwl_bt_uart_msg last_bt_uart_msg;
+       u8 bt_status; /* 0 - off, 1 - on */
+       u8 bt_traffic_load; /* 0 .. 3? */
+       u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
+       u8 reserved;
+} __attribute__((packed));
+
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS        0
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK        0x1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_POS          1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK         0x0e
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS      4
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK     0xf0
+#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT                1
+
+/*
+ * BT Coexistence Priority table
+ * REPLY_BT_COEX_PRIO_TABLE = 0xcc
+ */
+enum bt_coex_prio_table_events {
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+       BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+       BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+       BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+       BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
+       BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
+       BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
+       BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
+       BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
+       BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
+       BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
+       /* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
+       BT_COEX_PRIO_TBL_EVT_MAX,
+};
+
+enum bt_coex_prio_table_priorities {
+       BT_COEX_PRIO_TBL_DISABLED = 0,
+       BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+       BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+       BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+       BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+       BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
+       BT_COEX_PRIO_TBL_MAX,
+};
+
+struct iwl_bt_coex_prio_table_cmd {
+       u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __attribute__((packed));
+
+#define IWL_BT_COEX_ENV_CLOSE  0
+#define IWL_BT_COEX_ENV_OPEN   1
+/*
+ * BT Protection Envelope
+ * REPLY_BT_COEX_PROT_ENV = 0xcd
+ */
+struct iwl_bt_coex_prot_env_cmd {
+       u8 action; /* 0 = closed, 1 = open */
+       u8 type; /* 0 .. 15 */
+       u8 reserved[2];
+} __attribute__((packed));
+
 /******************************************************************************
  * (13)
  * Union of all expected notifications/responses:
@@ -4003,6 +4318,7 @@ struct iwl_rx_packet {
                struct iwl_missed_beacon_notif missed_beacon;
                struct iwl_coex_medium_notification coex_medium_notif;
                struct iwl_coex_event_resp coex_event;
+               struct iwl_bt_coex_profile_notif bt_coex_profile_notif;
                __le32 status;
                u8 raw[0];
        } u;
@@ -4010,4 +4326,94 @@ struct iwl_rx_packet {
 
 int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
 
+/*
+ * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
+ */
+
+/**
+ * struct iwl_wipan_slot
+ * @width: Time in TU
+ * @type:
+ *   0 - BSS
+ *   1 - PAN
+ */
+struct iwl_wipan_slot {
+       __le16 width;
+       u8 type;
+       u8 reserved;
+} __packed;
+
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS         BIT(1)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET       BIT(2)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE              BIT(3)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF       BIT(4)
+#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE         BIT(5)
+
+/**
+ * struct iwl_wipan_params_cmd
+ * @flags:
+ *   bit0: reserved
+ *   bit1: CP leave channel with CTS
+ *   bit2: CP leave channel qith Quiet
+ *   bit3: slotted mode
+ *     1 - work in slotted mode
+ *     0 - work in non slotted mode
+ *   bit4: filter beacon notification
+ *   bit5: full tx slotted mode. if this flag is set,
+ *         uCode will perform leaving channel methods in context switch
+ *         also when working in same channel mode
+ * @num_slots: 1 - 10
+ */
+struct iwl_wipan_params_cmd {
+       __le16 flags;
+       u8 reserved;
+       u8 num_slots;
+       struct iwl_wipan_slot slots[10];
+} __packed;
+
+/*
+ * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
+ *
+ * TODO: Figure out what this is used for,
+ *      it can only switch between 2.4 GHz
+ *      channels!!
+ */
+
+struct iwl_wipan_p2p_channel_switch_cmd {
+       __le16 channel;
+       __le16 reserved;
+};
+
+/*
+ * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
+ *
+ * This is used by the device to notify us of the
+ * NoA schedule it determined so we can forward it
+ * to userspace for inclusion in probe responses.
+ *
+ * In beacons, the NoA schedule is simply appended
+ * to the frame we give the device.
+ */
+
+struct iwl_wipan_noa_descriptor {
+       u8 count;
+       __le32 duration;
+       __le32 interval;
+       __le32 starttime;
+} __packed;
+
+struct iwl_wipan_noa_attribute {
+       u8 id;
+       __le16 length;
+       u8 index;
+       u8 ct_window;
+       struct iwl_wipan_noa_descriptor descr0, descr1;
+       u8 reserved;
+} __packed;
+
+struct iwl_wipan_noa_notification {
+       u32 noa_active;
+       struct iwl_wipan_noa_attribute noa_attribute;
+} __packed;
+
 #endif                         /* __iwl_commands_h__ */
index 3d9443b9bec14772774361e4793d789a1804fa68..87a2e40972ba85437a9fd26dd239244b2c1cf1fb 100644 (file)
@@ -64,7 +64,8 @@ MODULE_LICENSE("GPL");
  *
  * default: bt_coex_active = true (BT_COEX_ENABLE)
  */
-static bool bt_coex_active = true;
+bool bt_coex_active = true;
+EXPORT_SYMBOL_GPL(bt_coex_active);
 module_param(bt_coex_active, bool, S_IRUGO);
 MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
 
@@ -146,6 +147,10 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
        int i;
        u8 ind = ant;
 
+       if (priv->band == IEEE80211_BAND_2GHZ &&
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+               return 0;
+
        for (i = 0; i < RATE_ANT_NUM - 1; i++) {
                ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
                if (valid & BIT(ind))
@@ -186,27 +191,27 @@ EXPORT_SYMBOL(iwl_alloc_all);
 /*
  * QoS  support
 */
-static void iwl_update_qos(struct iwl_priv *priv)
+static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       priv->qos_data.def_qos_parm.qos_flags = 0;
+       ctx->qos_data.def_qos_parm.qos_flags = 0;
 
-       if (priv->qos_data.qos_active)
-               priv->qos_data.def_qos_parm.qos_flags |=
+       if (ctx->qos_data.qos_active)
+               ctx->qos_data.def_qos_parm.qos_flags |=
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
 
-       if (priv->current_ht_config.is_ht)
-               priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+       if (ctx->ht.enabled)
+               ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
        IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                     priv->qos_data.qos_active,
-                     priv->qos_data.def_qos_parm.qos_flags);
+                     ctx->qos_data.qos_active,
+                     ctx->qos_data.def_qos_parm.qos_flags);
 
-       iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+       iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
                               sizeof(struct iwl_qosparam_cmd),
-                              &priv->qos_data.def_qos_parm, NULL);
+                              &ctx->qos_data.def_qos_parm, NULL);
 }
 
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
@@ -436,15 +441,15 @@ static bool is_single_rx_stream(struct iwl_priv *priv)
               priv->current_ht_config.single_chain_sufficient;
 }
 
-static u8 iwl_is_channel_extension(struct iwl_priv *priv,
-                                  enum ieee80211_band band,
-                                  u16 channel, u8 extension_chan_offset)
+static bool iwl_is_channel_extension(struct iwl_priv *priv,
+                                    enum ieee80211_band band,
+                                    u16 channel, u8 extension_chan_offset)
 {
        const struct iwl_channel_info *ch_info;
 
        ch_info = iwl_get_channel_info(priv, band, channel);
        if (!is_channel_valid(ch_info))
-               return 0;
+               return false;
 
        if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
                return !(ch_info->ht40_extension_channel &
@@ -453,31 +458,31 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
                return !(ch_info->ht40_extension_channel &
                                        IEEE80211_CHAN_NO_HT40MINUS);
 
-       return 0;
+       return false;
 }
 
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                        struct ieee80211_sta_ht_cap *sta_ht_inf)
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap)
 {
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-
-       if (!ht_conf->is_ht || !ht_conf->is_40mhz)
-               return 0;
+       if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
+               return false;
 
-       /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
+       /*
+        * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
         * the bit will not set if it is pure 40MHz case
         */
-       if (sta_ht_inf) {
-               if (!sta_ht_inf->ht_supported)
-                       return 0;
-       }
+       if (ht_cap && !ht_cap->ht_supported)
+               return false;
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (priv->disable_ht40)
-               return 0;
+               return false;
 #endif
+
        return iwl_is_channel_extension(priv, priv->band,
-                       le16_to_cpu(priv->staging_rxon.channel),
-                       ht_conf->extension_chan_offset);
+                       le16_to_cpu(ctx->staging.channel),
+                       ctx->ht.extension_chan_offset);
 }
 EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
 
@@ -495,55 +500,64 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
        return new_val;
 }
 
-int iwl_send_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        u64 tsf;
        s32 interval_tm, rem;
        struct ieee80211_conf *conf = NULL;
        u16 beacon_int;
+       struct ieee80211_vif *vif = ctx->vif;
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
        lockdep_assert_held(&priv->mutex);
 
-       memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+       memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
 
-       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
-       priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+       ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
+       ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
 
-       beacon_int = vif->bss_conf.beacon_int;
+       beacon_int = vif ? vif->bss_conf.beacon_int : 0;
 
-       if (vif->type == NL80211_IFTYPE_ADHOC) {
-               /* TODO: we need to get atim_window from upper stack
-                * for now we set to 0 */
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               priv->rxon_timing.atim_window = 0;
-       }
+       /*
+        * TODO: For IBSS we need to get atim_window from mac80211,
+        *       for now just always use 0
+        */
+       ctx->timing.atim_window = 0;
 
-       beacon_int = iwl_adjust_beacon_interval(beacon_int,
+       if (ctx->ctxid == IWL_RXON_CTX_PAN &&
+           (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION)) {
+               ctx->timing.beacon_interval =
+                       priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
+               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+       } else {
+               beacon_int = iwl_adjust_beacon_interval(beacon_int,
                                priv->hw_params.max_beacon_itrvl * TIME_UNIT);
-       priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+               ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
+       }
 
        tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
        interval_tm = beacon_int * TIME_UNIT;
        rem = do_div(tsf, interval_tm);
-       priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+       ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+       ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
 
        IWL_DEBUG_ASSOC(priv,
                        "beacon interval %d beacon timer %d beacon tim %d\n",
-                       le16_to_cpu(priv->rxon_timing.beacon_interval),
-                       le32_to_cpu(priv->rxon_timing.beacon_init_val),
-                       le16_to_cpu(priv->rxon_timing.atim_window));
+                       le16_to_cpu(ctx->timing.beacon_interval),
+                       le32_to_cpu(ctx->timing.beacon_init_val),
+                       le16_to_cpu(ctx->timing.atim_window));
 
-       return iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                               sizeof(priv->rxon_timing), &priv->rxon_timing);
+       return iwl_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+                               sizeof(ctx->timing), &ctx->timing);
 }
 EXPORT_SYMBOL(iwl_send_rxon_timing);
 
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          int hw_decrypt)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        if (hw_decrypt)
                rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -560,11 +574,11 @@ EXPORT_SYMBOL(iwl_set_rxon_hwcrypto);
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-int iwl_check_rxon_cmd(struct iwl_priv *priv)
+int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        int error = 0;
        int counter = 1;
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
                error |= le32_to_cpu(rxon->flags &
@@ -636,66 +650,83 @@ EXPORT_SYMBOL(iwl_check_rxon_cmd);
  * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
  * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
-int iwl_full_rxon_required(struct iwl_priv *priv)
+int iwl_full_rxon_required(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx)
 {
+       const struct iwl_rxon_cmd *staging = &ctx->staging;
+       const struct iwl_rxon_cmd *active = &ctx->active;
+
+#define CHK(cond)                                                      \
+       if ((cond)) {                                                   \
+               IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");   \
+               return 1;                                               \
+       }
+
+#define CHK_NEQ(c1, c2)                                                \
+       if ((c1) != (c2)) {                                     \
+               IWL_DEBUG_INFO(priv, "need full RXON - "        \
+                              #c1 " != " #c2 " - %d != %d\n",  \
+                              (c1), (c2));                     \
+               return 1;                                       \
+       }
 
        /* These items are only settable from the full RXON command */
-       if (!(iwl_is_associated(priv)) ||
-           compare_ether_addr(priv->staging_rxon.bssid_addr,
-                              priv->active_rxon.bssid_addr) ||
-           compare_ether_addr(priv->staging_rxon.node_addr,
-                              priv->active_rxon.node_addr) ||
-           compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
-                              priv->active_rxon.wlap_bssid_addr) ||
-           (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
-           (priv->staging_rxon.channel != priv->active_rxon.channel) ||
-           (priv->staging_rxon.air_propagation !=
-            priv->active_rxon.air_propagation) ||
-           (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
-           (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
-           (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_triple_stream_basic_rates) ||
-           (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
-               return 1;
+       CHK(!iwl_is_associated_ctx(ctx));
+       CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr));
+       CHK(compare_ether_addr(staging->node_addr, active->node_addr));
+       CHK(compare_ether_addr(staging->wlap_bssid_addr,
+                               active->wlap_bssid_addr));
+       CHK_NEQ(staging->dev_type, active->dev_type);
+       CHK_NEQ(staging->channel, active->channel);
+       CHK_NEQ(staging->air_propagation, active->air_propagation);
+       CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
+               active->ofdm_ht_single_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
+               active->ofdm_ht_dual_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
+               active->ofdm_ht_triple_stream_basic_rates);
+       CHK_NEQ(staging->assoc_id, active->assoc_id);
 
        /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
         * be updated with the RXON_ASSOC command -- however only some
         * flag transitions are allowed using RXON_ASSOC */
 
        /* Check if we are not switching bands */
-       if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
-           (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
-               return 1;
+       CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
+               active->flags & RXON_FLG_BAND_24G_MSK);
 
        /* Check if we are switching association toggle */
-       if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
-               (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
-               return 1;
+       CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
+               active->filter_flags & RXON_FILTER_ASSOC_MSK);
+
+#undef CHK
+#undef CHK_NEQ
 
        return 0;
 }
 EXPORT_SYMBOL(iwl_full_rxon_required);
 
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx)
 {
        /*
         * Assign the lowest rate -- should really get this from
         * the beacon skb from mac80211.
         */
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK)
                return IWL_RATE_1M_PLCP;
        else
                return IWL_RATE_6M_PLCP;
 }
 EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
 
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+static void _iwl_set_rxon_ht(struct iwl_priv *priv,
+                            struct iwl_ht_config *ht_conf,
+                            struct iwl_rxon_context *ctx)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
-       if (!ht_conf->is_ht) {
+       if (!ctx->ht.enabled) {
                rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
                        RXON_FLG_HT40_PROT_MSK |
@@ -703,22 +734,22 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
                return;
        }
 
-       /* FIXME: if the definition of ht_protection changed, the "translation"
+       /* FIXME: if the definition of ht.protection changed, the "translation"
         * will be needed for rxon->flags
         */
-       rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+       rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS);
 
        /* Set up channel bandwidth:
         * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
        /* clear the HT channel mode before set the mode */
        rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
                         RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-       if (iwl_is_ht40_tx_allowed(priv, NULL)) {
+       if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
                /* pure ht40 */
-               if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+               if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
                        rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
                        /* Note: control channel is opposite of extension channel */
-                       switch (ht_conf->extension_chan_offset) {
+                       switch (ctx->ht.extension_chan_offset) {
                        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                                rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
                                break;
@@ -728,7 +759,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
                        }
                } else {
                        /* Note: control channel is opposite of extension channel */
-                       switch (ht_conf->extension_chan_offset) {
+                       switch (ctx->ht.extension_chan_offset) {
                        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                                rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
                                rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
@@ -749,12 +780,20 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
        }
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
        IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
                        "extension channel offset 0x%x\n",
-                       le32_to_cpu(rxon->flags), ht_conf->ht_protection,
-                       ht_conf->extension_chan_offset);
+                       le32_to_cpu(rxon->flags), ctx->ht.protection,
+                       ctx->ht.extension_chan_offset);
+}
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+{
+       struct iwl_rxon_context *ctx;
+
+       for_each_context(priv, ctx)
+               _iwl_set_rxon_ht(priv, ht_conf, ctx);
 }
 EXPORT_SYMBOL(iwl_set_rxon_ht);
 
@@ -775,6 +814,14 @@ 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)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               return IWL_NUM_RX_CHAINS_SINGLE;
+       }
        /* # of Rx chains to use when expecting MIMO. */
        if (is_single_rx_stream(priv))
                return IWL_NUM_RX_CHAINS_SINGLE;
@@ -819,7 +866,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
  * Selects how many and which Rx receivers/antennas/chains to use.
  * This should not be used for scan command ... it puts data in wrong place.
  */
-void iwl_set_rxon_chain(struct iwl_priv *priv)
+void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        bool is_single = is_single_rx_stream(priv);
        bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
@@ -831,11 +878,20 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
         * Before first association, we assume all antennas are connected.
         * Just after first association, iwl_chain_noise_calibration()
         *    checks which antennas actually *are* connected. */
-        if (priv->chain_noise_data.active_chains)
+       if (priv->chain_noise_data.active_chains)
                active_chains = priv->chain_noise_data.active_chains;
        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)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               active_chains = first_antenna(active_chains);
+       }
+
        rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
 
        /* How many receivers should we use? */
@@ -856,15 +912,15 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
        rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
        rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
 
-       priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+       ctx->staging.rx_chain = cpu_to_le16(rx_chain);
 
        if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
-               priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+               ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
        else
-               priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+               ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
 
        IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
-                       priv->staging_rxon.rx_chain,
+                       ctx->staging.rx_chain,
                        active_rx_cnt, idle_rx_cnt);
 
        WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
@@ -872,39 +928,41 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_set_rxon_chain);
 
-/* Return valid channel */
+/* Return valid, unused, channel for a passive scan to reset the RF */
 u8 iwl_get_single_channel_number(struct iwl_priv *priv,
-                                 enum ieee80211_band band)
+                                enum ieee80211_band band)
 {
        const struct iwl_channel_info *ch_info;
        int i;
        u8 channel = 0;
+       u8 min, max;
+       struct iwl_rxon_context *ctx;
 
-       /* only scan single channel, good enough to reset the RF */
-       /* pick the first valid not in-use channel */
        if (band == IEEE80211_BAND_5GHZ) {
-               for (i = 14; i < priv->channel_count; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                               channel = priv->channel_info[i].channel;
-                               ch_info = iwl_get_channel_info(priv,
-                                       band, channel);
-                               if (is_channel_valid(ch_info))
-                                       break;
-                       }
-               }
+               min = 14;
+               max = priv->channel_count;
        } else {
-               for (i = 0; i < 14; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                                       channel =
-                                               priv->channel_info[i].channel;
-                                       ch_info = iwl_get_channel_info(priv,
-                                               band, channel);
-                                       if (is_channel_valid(ch_info))
-                                               break;
-                       }
+               min = 0;
+               max = 14;
+       }
+
+       for (i = min; i < max; i++) {
+               bool busy = false;
+
+               for_each_context(priv, ctx) {
+                       busy = priv->channel_info[i].channel ==
+                               le16_to_cpu(ctx->staging.channel);
+                       if (busy)
+                               break;
                }
+
+               if (busy)
+                       continue;
+
+               channel = priv->channel_info[i].channel;
+               ch_info = iwl_get_channel_info(priv, band, channel);
+               if (is_channel_valid(ch_info))
+                       break;
        }
 
        return channel;
@@ -915,25 +973,24 @@ EXPORT_SYMBOL(iwl_get_single_channel_number);
  * iwl_set_rxon_channel - Set the band and channel values in staging RXON
  * @ch: requested channel as a pointer to struct ieee80211_channel
 
- * In addition to setting the staging RXON, priv->band is also set.
- *
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the ch->band
  */
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx)
 {
        enum ieee80211_band band = ch->band;
        u16 channel = ch->hw_value;
 
-       if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+       if ((le16_to_cpu(ctx->staging.channel) == channel) &&
            (priv->band == band))
                return 0;
 
-       priv->staging_rxon.channel = cpu_to_le16(channel);
+       ctx->staging.channel = cpu_to_le16(channel);
        if (band == IEEE80211_BAND_5GHZ)
-               priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
        else
-               priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
 
        priv->band = band;
 
@@ -944,24 +1001,25 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
 EXPORT_SYMBOL(iwl_set_rxon_channel);
 
 void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            enum ieee80211_band band,
                            struct ieee80211_vif *vif)
 {
        if (band == IEEE80211_BAND_5GHZ) {
-               priv->staging_rxon.flags &=
+               ctx->staging.flags &=
                    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
                      | RXON_FLG_CCK_MSK);
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
                /* Copied from iwl_post_associate() */
                if (vif && vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
-               priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
-               priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
+               ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
        }
 }
 EXPORT_SYMBOL(iwl_set_flags_for_band);
@@ -970,35 +1028,34 @@ EXPORT_SYMBOL(iwl_set_flags_for_band);
  * initialize rxon structure with default values from eeprom
  */
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif)
+                                  struct iwl_rxon_context *ctx)
 {
        const struct iwl_channel_info *ch_info;
-       enum nl80211_iftype type = NL80211_IFTYPE_STATION;
 
-       if (vif)
-               type = vif->type;
+       memset(&ctx->staging, 0, sizeof(ctx->staging));
 
-       memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
-
-       switch (type) {
+       if (!ctx->vif) {
+               ctx->staging.dev_type = ctx->unused_devtype;
+       } else switch (ctx->vif->type) {
        case NL80211_IFTYPE_AP:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+               ctx->staging.dev_type = ctx->ap_devtype;
                break;
 
        case NL80211_IFTYPE_STATION:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
-               priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+               ctx->staging.dev_type = ctx->station_devtype;
+               ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
                break;
 
        case NL80211_IFTYPE_ADHOC:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
-               priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
-               priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+               ctx->staging.dev_type = ctx->ibss_devtype;
+               ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
                                                  RXON_FILTER_ACCEPT_GRP_MSK;
                break;
 
        default:
-               IWL_ERR(priv, "Unsupported interface type %d\n", type);
+               IWL_ERR(priv, "Unsupported interface type %d\n",
+                       ctx->vif->type);
                break;
        }
 
@@ -1006,37 +1063,36 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
        /* TODO:  Figure out when short_preamble would be set and cache from
         * that */
        if (!hw_to_local(priv->hw)->short_preamble)
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 #endif
 
        ch_info = iwl_get_channel_info(priv, priv->band,
-                                      le16_to_cpu(priv->active_rxon.channel));
+                                      le16_to_cpu(ctx->active.channel));
 
        if (!ch_info)
                ch_info = &priv->channel_info[0];
 
-       priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+       ctx->staging.channel = cpu_to_le16(ch_info->channel);
        priv->band = ch_info->band;
 
-       iwl_set_flags_for_band(priv, priv->band, vif);
+       iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
 
-       priv->staging_rxon.ofdm_basic_rates =
+       ctx->staging.ofdm_basic_rates =
            (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-       priv->staging_rxon.cck_basic_rates =
+       ctx->staging.cck_basic_rates =
            (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
        /* clear both MIX and PURE40 mode flag */
-       priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+       ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
                                        RXON_FLG_CHANNEL_MODE_PURE_40);
+       if (ctx->vif)
+               memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
 
-       if (vif)
-               memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
-
-       priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
-       priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
-       priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
 }
 EXPORT_SYMBOL(iwl_connection_init_rx_config);
 
@@ -1044,6 +1100,7 @@ void iwl_set_rate(struct iwl_priv *priv)
 {
        const struct ieee80211_supported_band *hw = NULL;
        struct ieee80211_rate *rate;
+       struct iwl_rxon_context *ctx;
        int i;
 
        hw = iwl_get_hw_mode(priv, priv->band);
@@ -1062,21 +1119,29 @@ void iwl_set_rate(struct iwl_priv *priv)
 
        IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
 
-       priv->staging_rxon.cck_basic_rates =
-           (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+       for_each_context(priv, ctx) {
+               ctx->staging.cck_basic_rates =
+                   (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
-       priv->staging_rxon.ofdm_basic_rates =
-          (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+               ctx->staging.ofdm_basic_rates =
+                  (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+       }
 }
 EXPORT_SYMBOL(iwl_set_rate);
 
 void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (priv->switch_rxon.switch_in_progress) {
-               ieee80211_chswitch_done(priv->vif, is_success);
+               ieee80211_chswitch_done(ctx->vif, is_success);
                mutex_lock(&priv->mutex);
                priv->switch_rxon.switch_in_progress = false;
                mutex_unlock(&priv->mutex);
@@ -1087,14 +1152,19 @@ EXPORT_SYMBOL(iwl_chswitch_done);
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
        struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
        if (priv->switch_rxon.switch_in_progress) {
                if (!le32_to_cpu(csa->status) &&
                    (csa->channel == priv->switch_rxon.channel)) {
                        rxon->channel = csa->channel;
-                       priv->staging_rxon.channel = csa->channel;
+                       ctx->staging.channel = csa->channel;
                        IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
                              le16_to_cpu(csa->channel));
                        iwl_chswitch_done(priv, true);
@@ -1108,9 +1178,10 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 EXPORT_SYMBOL(iwl_rx_csa);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv)
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
        iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
@@ -1150,7 +1221,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
-               iwl_print_rx_config_cmd(priv);
+               iwl_print_rx_config_cmd(priv,
+                                       &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
        wake_up_interruptible(&priv->wait_command_queue);
@@ -1518,6 +1590,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                           const struct ieee80211_tx_queue_params *params)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx;
        unsigned long flags;
        int q;
 
@@ -1537,13 +1610,21 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
-       priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
-       priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-       priv->qos_data.def_qos_parm.ac[q].edca_txop =
-                       cpu_to_le16((params->txop * 32));
+       /*
+        * MULTI-FIXME
+        * This may need to be done per interface in nl80211/cfg80211/mac80211.
+        */
+       for_each_context(priv, ctx) {
+               ctx->qos_data.def_qos_parm.ac[q].cw_min =
+                       cpu_to_le16(params->cw_min);
+               ctx->qos_data.def_qos_parm.ac[q].cw_max =
+                       cpu_to_le16(params->cw_max);
+               ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+               ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                               cpu_to_le16((params->txop * 32));
 
-       priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+               ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1566,15 +1647,16 @@ static void iwl_ht_conf(struct iwl_priv *priv,
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
        struct ieee80211_sta *sta;
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 
        IWL_DEBUG_MAC80211(priv, "enter:\n");
 
-       if (!ht_conf->is_ht)
+       if (!ctx->ht.enabled)
                return;
 
-       ht_conf->ht_protection =
+       ctx->ht.protection =
                bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
-       ht_conf->non_GF_STA_present =
+       ctx->ht.non_gf_sta_present =
                !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
 
        ht_conf->single_chain_sufficient = false;
@@ -1618,18 +1700,20 @@ static void iwl_ht_conf(struct iwl_priv *priv,
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-static inline void iwl_set_no_assoc(struct iwl_priv *priv)
+static inline void iwl_set_no_assoc(struct iwl_priv *priv,
+                                   struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
        iwl_led_disassociate(priv);
        /*
         * inform the ucode that there is no longer an
         * association and that no more packets should be
         * sent
         */
-       priv->staging_rxon.filter_flags &=
-               ~RXON_FILTER_ASSOC_MSK;
-       priv->staging_rxon.assoc_id = 0;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ctx->staging.assoc_id = 0;
+       iwlcore_commit_rxon(priv, ctx);
 }
 
 static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -1640,6 +1724,14 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "update beacon but no beacon context!\n");
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
        if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
                return -EIO;
@@ -1658,7 +1750,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->cfg->ops->lib->post_associate(priv, priv->vif);
+       priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif);
 
        return 0;
 }
@@ -1669,6 +1761,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                          u32 changes)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        int ret;
 
        IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
@@ -1682,11 +1775,23 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                unsigned long flags;
 
                spin_lock_irqsave(&priv->lock, flags);
-               priv->qos_data.qos_active = bss_conf->qos;
-               iwl_update_qos(priv);
+               ctx->qos_data.qos_active = bss_conf->qos;
+               iwl_update_qos(priv, ctx);
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
+       if (changes & BSS_CHANGED_BEACON_ENABLED) {
+               /*
+                * the add_interface code must make sure we only ever
+                * have a single interface that could be beaconing at
+                * any time.
+                */
+               if (vif->bss_conf.enable_beacon)
+                       priv->beacon_ctx = ctx;
+               else
+                       priv->beacon_ctx = NULL;
+       }
+
        if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
                dev_kfree_skb(priv->ibss_beacon);
                priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
@@ -1713,13 +1818,13 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
                /* mac80211 only sets assoc when in STATION mode */
                if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
-                       memcpy(priv->staging_rxon.bssid_addr,
+                       memcpy(ctx->staging.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
 
                        /* currently needed in a few places */
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
                } else {
-                       priv->staging_rxon.filter_flags &=
+                       ctx->staging.filter_flags &=
                                ~RXON_FILTER_ASSOC_MSK;
                }
 
@@ -1742,21 +1847,21 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
                                   bss_conf->use_short_preamble);
                if (bss_conf->use_short_preamble)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        }
 
        if (changes & BSS_CHANGED_ERP_CTS_PROT) {
                IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
                if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
-                       priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+                       ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
                if (bss_conf->use_cts_prot)
-                       priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+                       ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+                       ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
        }
 
        if (changes & BSS_CHANGED_BASIC_RATES) {
@@ -1766,12 +1871,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                 * like this here:
                 *
                if (A-band)
-                       priv->staging_rxon.ofdm_basic_rates =
+                       ctx->staging.ofdm_basic_rates =
                                bss_conf->basic_rates;
                else
-                       priv->staging_rxon.ofdm_basic_rates =
+                       ctx->staging.ofdm_basic_rates =
                                bss_conf->basic_rates >> 4;
-                       priv->staging_rxon.cck_basic_rates =
+                       ctx->staging.cck_basic_rates =
                                bss_conf->basic_rates & 0xF;
                 */
        }
@@ -1780,7 +1885,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                iwl_ht_conf(priv, vif);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
        if (changes & BSS_CHANGED_ASSOC) {
@@ -1793,29 +1898,29 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        if (!iwl_is_rfkill(priv))
                                priv->cfg->ops->lib->post_associate(priv, vif);
                } else
-                       iwl_set_no_assoc(priv);
+                       iwl_set_no_assoc(priv, vif);
        }
 
-       if (changes && iwl_is_associated(priv) && bss_conf->aid) {
+       if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
                IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
                                   changes);
-               ret = iwl_send_rxon_assoc(priv);
+               ret = iwl_send_rxon_assoc(priv, ctx);
                if (!ret) {
                        /* Sync active_rxon with latest change. */
-                       memcpy((void *)&priv->active_rxon,
-                               &priv->staging_rxon,
+                       memcpy((void *)&ctx->active,
+                               &ctx->staging,
                                sizeof(struct iwl_rxon_cmd));
                }
        }
 
        if (changes & BSS_CHANGED_BEACON_ENABLED) {
                if (vif->bss_conf.enable_beacon) {
-                       memcpy(priv->staging_rxon.bssid_addr,
+                       memcpy(ctx->staging.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
                        iwlcore_config_ap(priv, vif);
                } else
-                       iwl_set_no_assoc(priv);
+                       iwl_set_no_assoc(priv, vif);
        }
 
        if (changes & BSS_CHANGED_IBSS) {
@@ -1827,6 +1932,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                bss_conf->bssid);
        }
 
+       if (changes & BSS_CHANGED_IDLE &&
+           priv->cfg->ops->hcmd->set_pan_params) {
+               if (priv->cfg->ops->hcmd->set_pan_params(priv))
+                       IWL_ERR(priv, "failed to update PAN params\n");
+       }
+
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1835,17 +1946,21 @@ EXPORT_SYMBOL(iwl_bss_info_changed);
 
 static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-       iwl_connection_init_rx_config(priv, vif);
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       iwl_connection_init_rx_config(priv, ctx);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       return iwlcore_commit_rxon(priv);
+       return iwlcore_commit_rxon(priv, ctx);
 }
 
 int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
        int err = 0;
 
        IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
@@ -1858,23 +1973,60 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                goto out;
        }
 
-       if (priv->vif) {
-               IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(vif->type)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       priv->vif = vif;
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
        priv->iw_mode = vif->type;
 
        err = iwl_set_mode(priv, vif);
        if (err)
                goto out_err;
 
+       if (priv->cfg->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
        goto out;
 
  out_err:
-       priv->vif = NULL;
+       ctx->vif = NULL;
        priv->iw_mode = NL80211_IFTYPE_STATION;
  out:
        mutex_unlock(&priv->mutex);
@@ -1888,26 +2040,36 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        bool scan_completed = false;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
        mutex_lock(&priv->mutex);
 
-       if (iwl_is_ready_rf(priv)) {
-               iwl_scan_cancel_timeout(priv, 100);
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
-       }
-       if (priv->vif == vif) {
-               priv->vif = NULL;
-               if (priv->scan_vif == vif) {
-                       scan_completed = true;
-                       priv->scan_vif = NULL;
-                       priv->scan_request = NULL;
-               }
-               memset(priv->bssid, 0, ETH_ALEN);
+       WARN_ON(ctx->vif != vif);
+       ctx->vif = NULL;
+
+       iwl_scan_cancel_timeout(priv, 100);
+       iwl_set_mode(priv, vif);
+
+       if (priv->scan_vif == vif) {
+               scan_completed = true;
+               priv->scan_vif = NULL;
+               priv->scan_request = NULL;
        }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->notif_bt_traffic_load;
+
+       memset(priv->bssid, 0, ETH_ALEN);
        mutex_unlock(&priv->mutex);
 
        if (scan_completed)
@@ -1928,6 +2090,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        struct ieee80211_conf *conf = &hw->conf;
        struct ieee80211_channel *channel = conf->channel;
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       struct iwl_rxon_context *ctx;
        unsigned long flags = 0;
        int ret = 0;
        u16 ch;
@@ -1957,7 +2120,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                 * configured.
                 */
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       for_each_context(priv, ctx)
+                               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
        /* during scanning mac80211 will delay channel setting until
@@ -1977,39 +2141,49 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 
                spin_lock_irqsave(&priv->lock, flags);
 
-               /* Configure HT40 channels */
-               ht_conf->is_ht = conf_is_ht(conf);
-               if (ht_conf->is_ht) {
-                       if (conf_is_ht40_minus(conf)) {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                               ht_conf->is_40mhz = true;
-                       } else if (conf_is_ht40_plus(conf)) {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                               ht_conf->is_40mhz = true;
-                       } else {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                               ht_conf->is_40mhz = false;
-                       }
-               } else
-                       ht_conf->is_40mhz = false;
-               /* Default to no protection. Protection mode will later be set
-                * from BSS config in iwl_ht_conf */
-               ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+               for_each_context(priv, ctx) {
+                       /* Configure HT40 channels */
+                       ctx->ht.enabled = conf_is_ht(conf);
+                       if (ctx->ht.enabled) {
+                               if (conf_is_ht40_minus(conf)) {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                                       ctx->ht.is_40mhz = true;
+                               } else if (conf_is_ht40_plus(conf)) {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                                       ctx->ht.is_40mhz = true;
+                               } else {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                                       ctx->ht.is_40mhz = false;
+                               }
+                       } else
+                               ctx->ht.is_40mhz = false;
 
-               if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
-                       priv->staging_rxon.flags = 0;
+                       /*
+                        * Default to no protection. Protection mode will
+                        * later be set from BSS config in iwl_ht_conf
+                        */
+                       ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+                       /* if we are switching from ht to 2.4 clear flags
+                        * from any ht related info since 2.4 does not
+                        * support ht */
+                       if ((le16_to_cpu(ctx->staging.channel) != ch))
+                               ctx->staging.flags = 0;
+
+                       iwl_set_rxon_channel(priv, channel, ctx);
+                       iwl_set_rxon_ht(priv, ht_conf);
 
-               iwl_set_rxon_channel(priv, channel);
-               iwl_set_rxon_ht(priv, ht_conf);
+                       iwl_set_flags_for_band(priv, ctx, channel->band,
+                                              ctx->vif);
+               }
 
-               iwl_set_flags_for_band(priv, channel->band, priv->vif);
                spin_unlock_irqrestore(&priv->lock, flags);
 
-               if (priv->cfg->ops->lib->update_bcast_station)
-                       ret = priv->cfg->ops->lib->update_bcast_station(priv);
+               if (priv->cfg->ops->lib->update_bcast_stations)
+                       ret = priv->cfg->ops->lib->update_bcast_stations(priv);
 
  set_ch_out:
                /* The list of supported rates and rate mask can be different
@@ -2040,12 +2214,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        if (scan_active)
                goto out;
 
-       if (memcmp(&priv->active_rxon,
-                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
-               iwlcore_commit_rxon(priv);
-       else
-               IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n");
-
+       for_each_context(priv, ctx) {
+               if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
+                       iwlcore_commit_rxon(priv, ctx);
+               else
+                       IWL_DEBUG_INFO(priv,
+                               "Not re-sending same RXON configuration.\n");
+       }
 
 out:
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2058,6 +2233,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
+       /* IBSS can only be the IWL_RXON_CTX_BSS context */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -2088,8 +2265,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
         * clear RXON_FILTER_ASSOC_MSK bit
         */
        iwl_scan_cancel_timeout(priv, 100);
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
        iwl_set_rate(priv);
 
@@ -2498,7 +2675,7 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_any_associated(priv)) {
                IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
                return;
        }
@@ -2624,10 +2801,14 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
                                                "queue %d, not read %d time\n",
                                                q->id,
                                                q->repeat_same_read_ptr);
-                               mod_timer(&priv->monitor_recover, jiffies +
-                                       msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
+                               if (!priv->cfg->advanced_bt_coexist) {
+                                       mod_timer(&priv->monitor_recover,
+                                               jiffies + msecs_to_jiffies(
+                                               IWL_ONE_HUNDRED_MSECS));
+                                       return 1;
+                               }
                        }
-                       return 1;
+                       return 0;
                } else {
                        q->last_read_ptr = q->read_ptr;
                        q->repeat_same_read_ptr = 0;
@@ -2645,25 +2826,27 @@ void iwl_bg_monitor_recover(unsigned long data)
                return;
 
        /* monitor and check for stuck cmd queue */
-       if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
+       if (iwl_check_stuck_queue(priv, priv->cmd_queue))
                return;
 
        /* monitor and check for other stuck queues */
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
                        /* skip as we already checked the command queue */
-                       if (cnt == IWL_CMD_QUEUE_NUM)
+                       if (cnt == priv->cmd_queue)
                                continue;
                        if (iwl_check_stuck_queue(priv, cnt))
                                return;
                }
        }
-       /*
-        * Reschedule the timer to occur in
-        * priv->cfg->monitor_recover_period
-        */
-       mod_timer(&priv->monitor_recover,
-               jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
+       if (priv->cfg->monitor_recover_period) {
+               /*
+                * Reschedule the timer to occur in
+                * priv->cfg->monitor_recover_period
+                */
+               mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+                         priv->cfg->monitor_recover_period));
+       }
 }
 EXPORT_SYMBOL(iwl_bg_monitor_recover);
 
index 7b1e832bae56a9e52b8ad6b8846e32e98a251e1b..f7b57ed84f66610d01e91b131cdae51970d09bed 100644 (file)
@@ -88,11 +88,13 @@ struct iwl_cmd;
 #define IWL_CMD(x) case x: return #x
 
 struct iwl_hcmd_ops {
-       int (*rxon_assoc)(struct iwl_priv *priv);
-       int (*commit_rxon)(struct iwl_priv *priv);
-       void (*set_rxon_chain)(struct iwl_priv *priv);
+       int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+       int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+       void (*set_rxon_chain)(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx);
        int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
        void (*send_bt_config)(struct iwl_priv *priv);
+       int (*set_pan_params)(struct iwl_priv *priv);
 };
 
 struct iwl_hcmd_utils_ops {
@@ -205,7 +207,7 @@ struct iwl_lib_ops {
        /* station management */
        int (*manage_ibss_station)(struct iwl_priv *priv,
                                   struct ieee80211_vif *vif, bool add);
-       int (*update_bcast_station)(struct iwl_priv *priv);
+       int (*update_bcast_stations)(struct iwl_priv *priv);
        /* recover from tx queue stall */
        void (*recover_from_tx_stall)(unsigned long data);
        /* check for plcp health */
@@ -278,6 +280,9 @@ struct iwl_mod_params {
  * @chain_noise_calib_by_driver: driver has the capability to perform
  *     chain noise calibration operation
  * @scan_antennas: available antenna for scan operation
+ * @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
@@ -351,6 +356,9 @@ struct iwl_cfg {
        const bool chain_noise_calib_by_driver;
        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;
@@ -368,21 +376,25 @@ void iwl_activate_qos(struct iwl_priv *priv);
 int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                    const struct ieee80211_tx_queue_params *params);
 int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
-int iwl_check_rxon_cmd(struct iwl_priv *priv);
-int iwl_full_rxon_required(struct iwl_priv *priv);
-void iwl_set_rxon_chain(struct iwl_priv *priv);
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          int hw_decrypt);
+int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx);
 void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            enum ieee80211_band band,
                            struct ieee80211_vif *vif);
 u8 iwl_get_single_channel_number(struct iwl_priv *priv,
                                  enum ieee80211_band band);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                        struct ieee80211_sta_ht_cap *sta_ht_inf);
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap);
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif);
+                                  struct iwl_rxon_context *ctx);
 void iwl_set_rate(struct iwl_priv *priv);
 int iwl_set_decrypted_flag(struct iwl_priv *priv,
                           struct ieee80211_hdr *hdr,
@@ -394,7 +406,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
                                     u32 changes);
-int iwl_commit_rxon(struct iwl_priv *priv);
+int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
                          struct ieee80211_vif *vif);
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
@@ -512,7 +524,8 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
 
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
 
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx);
 
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
 
@@ -626,9 +639,11 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv,
 void iwl_dump_csr(struct iwl_priv *priv);
 int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv);
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx);
 #else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv)
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                                          struct iwl_rxon_context *ctx)
 {
 }
 #endif
@@ -708,19 +723,21 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
 extern void iwl_send_bt_config(struct iwl_priv *priv);
 extern int iwl_send_statistics_request(struct iwl_priv *priv,
                                       u8 flags, bool clear);
-extern int iwl_send_lq_cmd(struct iwl_priv *priv,
+extern int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                struct iwl_link_quality_cmd *lq, u8 flags, bool init);
 void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
-int iwl_send_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+static inline int iwl_send_rxon_assoc(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx)
 {
-       return priv->cfg->ops->hcmd->rxon_assoc(priv);
+       return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
 }
-static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
+static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx)
 {
-       return priv->cfg->ops->hcmd->commit_rxon(priv);
+       return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
 }
 static inline void iwlcore_config_ap(struct iwl_priv *priv,
                                     struct ieee80211_vif *vif)
@@ -732,4 +749,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
 {
        return priv->hw->wiphy->bands[band];
 }
+
+extern bool bt_coex_active;
+extern bool bt_siso_mode;
+
 #endif /* __iwl_core_h__ */
index d3acdae7238128e0fe9d292a25bbd03a2c33ac32..0ee8f516c4ab0e4b1711f32792ec89d84c52a65f 100644 (file)
@@ -643,19 +643,25 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
                                       size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
+       struct iwl_rxon_context *ctx;
        int pos = 0, i;
-       char buf[256];
+       char buf[256 * NUM_IWL_RXON_CTX];
        const size_t bufsz = sizeof(buf);
 
-       for (i = 0; i < AC_NUM; i++) {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tcw_min\tcw_max\taifsn\ttxop\n");
-               pos += scnprintf(buf + pos, bufsz - pos,
+       for_each_context(priv, ctx) {
+               pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
+                                ctx->ctxid);
+               for (i = 0; i < AC_NUM; i++) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "\tcw_min\tcw_max\taifsn\ttxop\n");
+                       pos += scnprintf(buf + pos, bufsz - pos,
                                "AC[%d]\t%u\t%u\t%u\t%u\n", i,
-                               priv->qos_data.def_qos_parm.ac[i].cw_min,
-                               priv->qos_data.def_qos_parm.ac[i].cw_max,
-                               priv->qos_data.def_qos_parm.ac[i].aifsn,
-                               priv->qos_data.def_qos_parm.ac[i].edca_txop);
+                               ctx->qos_data.def_qos_parm.ac[i].cw_min,
+                               ctx->qos_data.def_qos_parm.ac[i].cw_max,
+                               ctx->qos_data.def_qos_parm.ac[i].aifsn,
+                               ctx->qos_data.def_qos_parm.ac[i].edca_txop);
+               }
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
        }
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -730,7 +736,7 @@ static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
                return -EFAULT;
        if (sscanf(buf, "%d", &ht40) != 1)
                return -EFAULT;
-       if (!iwl_is_associated(priv))
+       if (!iwl_is_any_associated(priv))
                priv->disable_ht40 = ht40 ? true : false;
        else {
                IWL_ERR(priv, "Sta associated with AP - "
@@ -1319,7 +1325,8 @@ static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
        int len = 0;
        char buf[20];
 
-       len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
+       len = sprintf(buf, "0x%04X\n",
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -1332,7 +1339,7 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
        char buf[20];
 
        len = sprintf(buf, "0x%04X\n",
-                     le32_to_cpu(priv->active_rxon.filter_flags));
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -1527,6 +1534,76 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
                        user_buf, count, ppos);
 }
 
+static ssize_t iwl_dbgfs_monitor_period_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int period;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       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;
+       else
+               priv->cfg->monitor_recover_period = period;
+
+       if (priv->cfg->monitor_recover_period)
+               mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+                         priv->cfg->monitor_recover_period));
+       else
+               del_timer_sync(&priv->monitor_recover);
+       return count;
+}
+
+static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[200];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
+               priv->bt_full_concurrent ? "full concurrency" : "3-wire");
+       pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
+                        "last traffic notif: %d\n",
+               priv->bt_status ? "On" : "Off", priv->notif_bt_traffic_load);
+       pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
+                        "sco_active: %d, kill_ack_mask: %x, "
+                        "kill_cts_mask: %x\n",
+               priv->bt_ch_announce, priv->bt_sco_active,
+               priv->kill_ack_mask, priv->kill_cts_mask);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+               pos += scnprintf(buf + pos, bufsz - pos, "High\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+       default:
+               pos += scnprintf(buf + pos, bufsz - pos, "None\n");
+               break;
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1550,6 +1627,8 @@ DEBUGFS_READ_FILE_OPS(rxon_flags);
 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
 DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
 DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
+DEBUGFS_WRITE_FILE_OPS(monitor_period);
+DEBUGFS_READ_FILE_OPS(bt_traffic);
 
 /*
  * Create the debugfs files and directories
@@ -1621,6 +1700,9 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
                DEBUGFS_ADD_FILE(ucode_bt_stats, 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)
+               DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
        if (priv->cfg->sensitivity_calib_by_driver)
                DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
                                 &priv->disable_sens_cal);
index 1ad330342ffc605f0938bfc6fd24b1183a14a623..4dd38b7b8b743a1614678bab5732788c779e46fc 100644 (file)
@@ -144,6 +144,7 @@ struct iwl_queue {
 /* One for each TFD */
 struct iwl_tx_info {
        struct sk_buff *skb;
+       struct iwl_rxon_context *ctx;
 };
 
 /**
@@ -253,10 +254,14 @@ struct iwl_channel_info {
        struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
 };
 
-#define IWL_TX_FIFO_BK         0
+#define IWL_TX_FIFO_BK         0       /* shared */
 #define IWL_TX_FIFO_BE         1
-#define IWL_TX_FIFO_VI         2
+#define IWL_TX_FIFO_VI         2       /* shared */
 #define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN    4
+#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN    5
 #define IWL_TX_FIFO_UNUSED     -1
 
 /* Minimum number of queues. MAX_NUM is defined in hw specific files.
@@ -265,11 +270,17 @@ struct iwl_channel_info {
 #define IWL_MIN_NUM_QUEUES     10
 
 /*
- * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00,
- * the driver maps it into the appropriate device FIFO for the
- * uCode.
+ * Command queue depends on iPAN support.
  */
-#define IWL_CMD_QUEUE_NUM      4
+#define IWL_DEFAULT_CMD_QUEUE_NUM      4
+#define IWL_IPAN_CMD_QUEUE_NUM         9
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE           8
 
 /* Power management (not Tx power) structures */
 
@@ -459,15 +470,8 @@ union iwl_ht_rate_supp {
 #define CFG_HT_MPDU_DENSITY_MIN     (0x1)
 
 struct iwl_ht_config {
-       /* self configuration data */
-       bool is_ht;
-       bool is_40mhz;
        bool single_chain_sufficient;
        enum ieee80211_smps_mode smps; /* current smps mode */
-       /* BSS related data */
-       u8 extension_chan_offset;
-       u8 ht_protection;
-       u8 non_GF_STA_present;
 };
 
 /* QoS structures */
@@ -485,12 +489,13 @@ struct iwl_qos_info {
 struct iwl_station_entry {
        struct iwl_addsta_cmd sta;
        struct iwl_tid_data tid[MAX_TID_COUNT];
-       u8 used;
+       u8 used, ctxid;
        struct iwl_hw_key keyinfo;
        struct iwl_link_quality_cmd *lq;
 };
 
 struct iwl_station_priv_common {
+       struct iwl_rxon_context *ctx;
        u8 sta_id;
 };
 
@@ -519,6 +524,7 @@ struct iwl_station_priv {
  * space for us to put data into.
  */
 struct iwl_vif_priv {
+       struct iwl_rxon_context *ctx;
        u8 ibss_bssid_sta_id;
 };
 
@@ -576,6 +582,7 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_INIT_DATA         = 4,
        IWL_UCODE_TLV_BOOT              = 5,
        IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
+       IWL_UCODE_TLV_PAN               = 7,
        IWL_UCODE_TLV_RUNT_EVTLOG_PTR   = 8,
        IWL_UCODE_TLV_RUNT_EVTLOG_SIZE  = 9,
        IWL_UCODE_TLV_RUNT_ERRLOG_PTR   = 10,
@@ -670,7 +677,6 @@ struct iwl_sensitivity_ranges {
  * @rx_page_order: Rx buffer page order
  * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
  * @max_stations:
- * @bcast_sta_id:
  * @ht40_channel: is 40MHz width possible in band 2.4
  * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
  * @sw_crypto: 0 for hw, 1 for sw
@@ -694,7 +700,6 @@ struct iwl_hw_params {
        u32 rx_page_order;
        u32 rx_wrt_ptr_reg;
        u8  max_stations;
-       u8  bcast_sta_id;
        u8  ht40_channel;
        u8  max_beacon_itrvl;   /* in 1024 ms */
        u32 max_inst_size;
@@ -1064,6 +1069,10 @@ struct iwl_event_log {
 #define IWL_DEF_MONITORING_PERIOD      (1000)
 #define IWL_LONG_MONITORING_PERIOD     (5000)
 #define IWL_ONE_HUNDRED_MSECS   (100)
+#define IWL_MAX_MONITORING_PERIOD      (60000)
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD      (35)
 
 enum iwl_reset {
        IWL_RF_RESET = 0,
@@ -1093,6 +1102,57 @@ struct iwl_force_reset {
  */
 #define IWLAGN_EXT_BEACON_TIME_POS     22
 
+enum iwl_rxon_context_id {
+       IWL_RXON_CTX_BSS,
+       IWL_RXON_CTX_PAN,
+
+       NUM_IWL_RXON_CTX
+};
+
+struct iwl_rxon_context {
+       struct ieee80211_vif *vif;
+
+       const u8 *ac_to_fifo;
+       const u8 *ac_to_queue;
+       u8 mcast_queue;
+
+       enum iwl_rxon_context_id ctxid;
+
+       u32 interface_modes, exclusive_interface_modes;
+       u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
+
+       /*
+        * We declare this const so it can only be
+        * changed via explicit cast within the
+        * routines that actually update the physical
+        * hardware.
+        */
+       const struct iwl_rxon_cmd active;
+       struct iwl_rxon_cmd staging;
+
+       struct iwl_rxon_time_cmd timing;
+
+       struct iwl_qos_info qos_data;
+
+       u8 bcast_sta_id, ap_sta_id;
+
+       u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
+       u8 qos_cmd;
+       u8 wep_key_cmd;
+
+       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+       u8 key_mapping_keys;
+
+       __le32 station_flags;
+
+       struct {
+               bool non_gf_sta_present;
+               u8 protection;
+               bool enabled, is_40mhz;
+               u8 extension_chan_offset;
+       } ht;
+};
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1169,6 +1229,15 @@ struct iwl_priv {
        u32  hw_wa_rev;
        u8   rev_id;
 
+       /* microcode/device supports multiple contexts */
+       u8 valid_contexts;
+
+       /* command queue number */
+       u8 cmd_queue;
+
+       /* max number of station keys */
+       u8 sta_key_max_num;
+
        /* EEPROM MAC addresses */
        struct mac_address addresses[2];
 
@@ -1186,15 +1255,7 @@ struct iwl_priv {
        u8 ucode_write_complete;        /* the image write is complete */
        char firmware_name[25];
 
-
-       struct iwl_rxon_time_cmd rxon_timing;
-
-       /* We declare this const so it can only be
-        * changed via explicit cast within the
-        * routines that actually update the physical
-        * hardware */
-       const struct iwl_rxon_cmd active_rxon;
-       struct iwl_rxon_cmd staging_rxon;
+       struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
        struct iwl_switch_rxon switch_rxon;
 
@@ -1256,8 +1317,6 @@ struct iwl_priv {
        spinlock_t sta_lock;
        int num_stations;
        struct iwl_station_entry stations[IWL_STATION_COUNT];
-       struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
-       u8 key_mapping_key;
        unsigned long ucode_key_table;
 
        /* queue refcounts */
@@ -1282,7 +1341,6 @@ struct iwl_priv {
 
        /* Last Rx'd beacon timestamp */
        u64 timestamp;
-       struct ieee80211_vif *vif;
 
        union {
 #if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
@@ -1362,12 +1420,27 @@ struct iwl_priv {
 #endif
        };
 
+       /* bt coex */
+       u8 bt_status;
+       u8 bt_traffic_load, notif_bt_traffic_load;
+       bool bt_ch_announce;
+       bool bt_sco_active;
+       bool bt_full_concurrent;
+       bool bt_ant_couple_ok;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       __le16 bt_valid;
+       u16 bt_on_thresh;
+       u16 bt_duration;
+       u16 dynamic_frag_thresh;
+       u16 dynamic_agg_thresh;
+       u8 bt_ci_compliance;
+       struct work_struct bt_traffic_change_work;
+
        struct iwl_hw_params hw_params;
 
        u32 inta_mask;
 
-       struct iwl_qos_info qos_data;
-
        struct workqueue_struct *workqueue;
 
        struct work_struct restart;
@@ -1375,11 +1448,15 @@ struct iwl_priv {
        struct work_struct rx_replenish;
        struct work_struct abort_scan;
        struct work_struct beacon_update;
+       struct iwl_rxon_context *beacon_ctx;
+
        struct work_struct tt_work;
        struct work_struct ct_enter;
        struct work_struct ct_exit;
        struct work_struct start_internal_scan;
        struct work_struct tx_flush;
+       struct work_struct bt_full_concurrency;
+       struct work_struct bt_runtime_config;
 
        struct tasklet_struct irq_tasklet;
 
@@ -1467,10 +1544,34 @@ static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
        return NULL;
 }
 
+static inline struct iwl_rxon_context *
+iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       return vif_priv->ctx;
+}
+
+#define for_each_context(priv, ctx)                            \
+       for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];           \
+            ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)    \
+               if (priv->valid_contexts & BIT(ctx->ctxid))
+
+static inline int iwl_is_associated(struct iwl_priv *priv,
+                                   enum iwl_rxon_context_id ctxid)
+{
+       return (priv->contexts[ctxid].active.filter_flags &
+                       RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
+{
+       return iwl_is_associated(priv, IWL_RXON_CTX_BSS);
+}
 
-static inline int iwl_is_associated(struct iwl_priv *priv)
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
 {
-       return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+       return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
 }
 
 static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
index 258d059ef41f44ae01e4199327133655b5e6df1e..c373b53babeaee1cd1c4e7781151e683e305f2ba 100644 (file)
@@ -97,6 +97,17 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_TX_POWER_DBM_CMD);
                IWL_CMD(TEMPERATURE_NOTIFICATION);
                IWL_CMD(TX_ANT_CONFIGURATION_CMD);
+               IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
+               IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
+               IWL_CMD(REPLY_BT_COEX_PROT_ENV);
+               IWL_CMD(REPLY_WIPAN_PARAMS);
+               IWL_CMD(REPLY_WIPAN_RXON);
+               IWL_CMD(REPLY_WIPAN_RXON_TIMING);
+               IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
+               IWL_CMD(REPLY_WIPAN_QOS_PARAM);
+               IWL_CMD(REPLY_WIPAN_WEPKEY);
+               IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
+               IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
        default:
                return "UNKNOWN";
 
@@ -229,7 +240,7 @@ cancel:
                 * in later, it will possibly set an invalid
                 * address (cmd->meta.source).
                 */
-               priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+               priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
 fail:
index b1f101caf19d2f063386453c7cd1f8e045e7b10d..5469655646aebaa72cf673a942e4f127bd3fa5e5 100644 (file)
  *     at a time, until receiving ACK from receiving station, or reaching
  *     retry limit and giving up.
  *
- *     The command queue (#4) must use this mode!
+ *     The command queue (#4/#9) must use this mode!
  *     This mode does not require use of the Byte Count table in host DRAM.
  *
  * Driver controls scheduler operation via 3 means:
  *     (1024 bytes for each queue).
  *
  * After receiving "Alive" response from uCode, driver must initialize
- * the scheduler (especially for queue #4, the command queue, otherwise
+ * the scheduler (especially for queue #4/#9, the command queue, otherwise
  * the driver can't issue commands!):
  */
 
 #define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
        ((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
 
-#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(x)               (((1<<(x)) - 1) &\
-       (~(1<<IWL_CMD_QUEUE_NUM)))
+#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv)    \
+       (((1<<(priv)->hw_params.max_txq_num) - 1) &\
+       (~(1<<(priv)->cmd_queue)))
 
 #define IWLAGN_SCD_BASE                        (PRPH_BASE + 0xa02c00)
 
index 79773e353baaa56478a6d173fdc5f0f70cf837fa..10be197b0f2294b92643baf5a96d4ebd141552c7 100644 (file)
@@ -228,7 +228,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                if (priv->cfg->ops->lib->check_ack_health) {
                        if (!priv->cfg->ops->lib->check_ack_health(
                            priv, pkt)) {
@@ -266,7 +266,12 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
 {
        u16 fc = le16_to_cpu(hdr->frame_control);
 
-       if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+       /*
+        * All contexts have the same setting here due to it being
+        * a module parameter, so OK to check any context.
+        */
+       if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
+                                               RXON_FILTER_DIS_DECRYPT_MSK)
                return 0;
 
        if (!(fc & IEEE80211_FCTL_PROTECTED))
index 8d7fa59364feaa455ace2c23348e6cecb87be75f..7727f0966d3168e971dad3c6ffd03d3e45c54369 100644 (file)
@@ -206,7 +206,6 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                                       struct iwl_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
@@ -214,7 +213,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                       scan_notif->scanned_channels,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
-#endif
 
        /* The HW is no longer scanning */
        clear_bit(STATUS_SCAN_HW, &priv->status);
@@ -236,6 +234,26 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
 
        clear_bit(STATUS_SCANNING, &priv->status);
 
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
+           priv->cfg->advanced_bt_coexist && priv->bt_status !=
+           scan_notif->bt_status) {
+               if (scan_notif->bt_status) {
+                       /* BT on */
+                       if (!priv->bt_ch_announce)
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                       /*
+                        * otherwise, no traffic load information provided
+                        * no changes made
+                        */
+               } else {
+                       /* BT off */
+                       priv->bt_traffic_load =
+                               IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+               }
+               priv->bt_status = scan_notif->bt_status;
+               queue_work(priv->workqueue, &priv->bt_traffic_change_work);
+       }
        queue_work(priv->workqueue, &priv->scan_completed);
 }
 
@@ -268,18 +286,28 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                               enum ieee80211_band band,
                               struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx;
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-       if (iwl_is_associated(priv)) {
-               /* If we're associated, we clamp the maximum passive
-                * dwell time to be 98% of the beacon interval (minus
-                * 2 * channel tune time) */
-               passive = vif ? vif->bss_conf.beacon_int : 0;
-               if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
-                       passive = IWL_PASSIVE_DWELL_BASE;
-               passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+       if (iwl_is_any_associated(priv)) {
+               /*
+                * If we're associated, we clamp the maximum passive
+                * dwell time to be 98% of the smallest beacon interval
+                * (minus 2 * channel tune time)
+                */
+               for_each_context(priv, ctx) {
+                       u16 value;
+
+                       if (!iwl_is_associated_ctx(ctx))
+                               continue;
+                       value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
+                       if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
+                               value = IWL_PASSIVE_DWELL_BASE;
+                       value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+                       passive = min(value, passive);
+               }
        }
 
        return passive;
@@ -509,6 +537,7 @@ static void iwl_bg_scan_completed(struct work_struct *work)
            container_of(work, struct iwl_priv, scan_completed);
        bool internal = false;
        bool scan_completed = false;
+       struct iwl_rxon_context *ctx;
 
        IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
@@ -539,11 +568,13 @@ static void iwl_bg_scan_completed(struct work_struct *work)
         * Since setting the RXON may have been deferred while
         * performing the scan, fire one off if needed
         */
-       if (memcmp(&priv->active_rxon,
-                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
-               iwlcore_commit_rxon(priv);
+       for_each_context(priv, ctx)
+               iwlcore_commit_rxon(priv, ctx);
 
  out:
+       if (priv->cfg->ops->hcmd->set_pan_params)
+               priv->cfg->ops->hcmd->set_pan_params(priv);
+
        mutex_unlock(&priv->mutex);
 
        /*
index d5e8db37b86e6f442aa673015c7bded2be4b3f9a..ccd09027c7cdd8f3a1b479e6fda1215c960bd102 100644 (file)
@@ -172,12 +172,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_send_add_sta);
 
 static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                                  struct ieee80211_sta_ht_cap *sta_ht_inf)
+                                  struct ieee80211_sta *sta,
+                                  struct iwl_rxon_context *ctx)
 {
+       struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
        __le32 sta_flags;
        u8 mimo_ps_mode;
 
-       if (!sta_ht_inf || !sta_ht_inf->ht_supported)
+       if (!sta || !sta_ht_inf->ht_supported)
                goto done;
 
        mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
@@ -211,7 +213,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
        sta_flags |= cpu_to_le32(
              (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
-       if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                sta_flags |= STA_FLG_HT40_EN_MSK;
        else
                sta_flags &= ~STA_FLG_HT40_EN_MSK;
@@ -226,9 +228,9 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
  *
  * should be called with sta_lock held
  */
-static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
-                          bool is_ap,
-                          struct ieee80211_sta_ht_cap *ht_info)
+static u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta)
 {
        struct iwl_station_entry *station;
        int i;
@@ -236,9 +238,9 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
        u16 rate;
 
        if (is_ap)
-               sta_id = IWL_AP_ID;
+               sta_id = ctx->ap_sta_id;
        else if (is_broadcast_ether_addr(addr))
-               sta_id = priv->hw_params.bcast_sta_id;
+               sta_id = ctx->bcast_sta_id;
        else
                for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
                        if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
@@ -289,14 +291,22 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
        memcpy(station->sta.sta.addr, addr, ETH_ALEN);
        station->sta.mode = 0;
        station->sta.sta.sta_id = sta_id;
-       station->sta.station_flags = 0;
+       station->sta.station_flags = ctx->station_flags;
+       station->ctxid = ctx->ctxid;
+
+       if (sta) {
+               struct iwl_station_priv_common *sta_priv;
+
+               sta_priv = (void *)sta->drv_priv;
+               sta_priv->ctx = ctx;
+       }
 
        /*
         * OK to call unconditionally, since local stations (IBSS BSSID
-        * STA and broadcast STA) pass in a NULL ht_info, and mac80211
+        * STA and broadcast STA) pass in a NULL sta, and mac80211
         * doesn't allow HT IBSS.
         */
-       iwl_set_ht_add_station(priv, sta_id, ht_info);
+       iwl_set_ht_add_station(priv, sta_id, sta, ctx);
 
        /* 3945 only */
        rate = (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -313,10 +323,9 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
 /**
  * iwl_add_station_common -
  */
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
-                                 bool is_ap,
-                                 struct ieee80211_sta_ht_cap *ht_info,
-                                 u8 *sta_id_r)
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r)
 {
        unsigned long flags_spin;
        int ret = 0;
@@ -325,7 +334,7 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
 
        *sta_id_r = 0;
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
-       sta_id = iwl_prep_station(priv, addr, is_ap, ht_info);
+       sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
                        addr);
@@ -431,8 +440,8 @@ static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
  *
  * Function sleeps.
  */
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
-                         u8 *sta_id_r)
+int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                         const u8 *addr, bool init_rs, u8 *sta_id_r)
 {
        int ret;
        u8 sta_id;
@@ -442,7 +451,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
        if (sta_id_r)
                *sta_id_r = IWL_INVALID_STATION;
 
-       ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
+       ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM\n", addr);
                return ret;
@@ -464,7 +473,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
                        return -ENOMEM;
                }
 
-               ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true);
+               ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
                if (ret)
                        IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
 
@@ -616,7 +625,8 @@ EXPORT_SYMBOL_GPL(iwl_remove_station);
  * other than explicit station management would cause this in
  * the ucode, e.g. unassociated RXON.
  */
-void iwl_clear_ucode_stations(struct iwl_priv *priv)
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx)
 {
        int i;
        unsigned long flags_spin;
@@ -626,6 +636,9 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv)
 
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (ctx && ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
+
                if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
                        IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
                        priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
@@ -647,7 +660,7 @@ EXPORT_SYMBOL(iwl_clear_ucode_stations);
  *
  * Function sleeps.
  */
-void iwl_restore_stations(struct iwl_priv *priv)
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
@@ -665,6 +678,8 @@ void iwl_restore_stations(struct iwl_priv *priv)
        IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
                if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
                            !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
                        IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
@@ -700,7 +715,7 @@ void iwl_restore_stations(struct iwl_priv *priv)
                         * current LQ command
                         */
                        if (send_lq)
-                               iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
+                               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
                        spin_lock_irqsave(&priv->sta_lock, flags_spin);
                        priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
                }
@@ -718,7 +733,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
        int i;
 
-       for (i = 0; i < STA_KEY_MAX_NUM; i++)
+       for (i = 0; i < priv->sta_key_max_num; i++)
                if (!test_and_set_bit(i, &priv->ucode_key_table))
                        return i;
 
@@ -726,7 +741,9 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
 
-static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx,
+                                     bool send_if_empty)
 {
        int i, not_empty = 0;
        u8 buff[sizeof(struct iwl_wep_cmd) +
@@ -734,7 +751,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
        size_t cmd_size  = sizeof(struct iwl_wep_cmd);
        struct iwl_host_cmd cmd = {
-               .id = REPLY_WEPKEY,
+               .id = ctx->wep_key_cmd,
                .data = wep_cmd,
                .flags = CMD_SYNC,
        };
@@ -746,16 +763,16 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 
        for (i = 0; i < WEP_KEYS_MAX ; i++) {
                wep_cmd->key[i].key_index = i;
-               if (priv->wep_keys[i].key_size) {
+               if (ctx->wep_keys[i].key_size) {
                        wep_cmd->key[i].key_offset = i;
                        not_empty = 1;
                } else {
                        wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
                }
 
-               wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
-               memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
-                               priv->wep_keys[i].key_size);
+               wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
+               memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
+                               ctx->wep_keys[i].key_size);
        }
 
        wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
@@ -771,15 +788,17 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
                return 0;
 }
 
-int iwl_restore_default_wep_keys(struct iwl_priv *priv)
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx)
 {
        lockdep_assert_held(&priv->mutex);
 
-       return iwl_send_static_wepkey_cmd(priv, 0);
+       return iwl_send_static_wepkey_cmd(priv, ctx, false);
 }
 EXPORT_SYMBOL(iwl_restore_default_wep_keys);
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
                               struct ieee80211_key_conf *keyconf)
 {
        int ret;
@@ -789,13 +808,13 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
        IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
                      keyconf->keyidx);
 
-       memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+       memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
                /* but keys in device are clear anyway so return success */
                return 0;
        }
-       ret = iwl_send_static_wepkey_cmd(priv, 1);
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
        IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
                      keyconf->keyidx, ret);
 
@@ -804,6 +823,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_remove_default_wep_key);
 
 int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            struct ieee80211_key_conf *keyconf)
 {
        int ret;
@@ -818,13 +838,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 
        keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
        keyconf->hw_key_idx = HW_KEY_DEFAULT;
-       priv->stations[IWL_AP_ID].keyinfo.cipher = keyconf->cipher;
+       priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher;
 
-       priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
-       memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
+       ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+       memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
                                                        keyconf->keylen);
 
-       ret = iwl_send_static_wepkey_cmd(priv, 0);
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
        IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
                keyconf->keylen, keyconf->keyidx, ret);
 
@@ -833,8 +853,9 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_set_default_wep_key);
 
 static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf,
-                               u8 sta_id)
+                                       struct iwl_rxon_context *ctx,
+                                       struct ieee80211_key_conf *keyconf,
+                                       u8 sta_id)
 {
        unsigned long flags;
        __le16 key_flags = 0;
@@ -851,7 +872,7 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
        if (keyconf->keylen == WEP_KEY_LEN_128)
                key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
@@ -887,8 +908,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
 }
 
 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
+                                        struct iwl_rxon_context *ctx,
+                                        struct ieee80211_key_conf *keyconf,
+                                        u8 sta_id)
 {
        unsigned long flags;
        __le16 key_flags = 0;
@@ -900,7 +922,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags &= ~STA_KEY_FLG_INVALID;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -936,8 +958,9 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
 }
 
 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
+                                        struct iwl_rxon_context *ctx,
+                                        struct ieee80211_key_conf *keyconf,
+                                        u8 sta_id)
 {
        unsigned long flags;
        int ret = 0;
@@ -947,7 +970,7 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags &= ~STA_KEY_FLG_INVALID;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -982,8 +1005,9 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 }
 
 void iwl_update_tkip_key(struct iwl_priv *priv,
-                       struct ieee80211_key_conf *keyconf,
-                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
+                        struct iwl_rxon_context *ctx,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
 {
        u8 sta_id;
        unsigned long flags;
@@ -995,7 +1019,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
                return;
        }
 
-       sta_id = iwl_sta_id_or_broadcast(priv, sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta);
        if (sta_id == IWL_INVALID_STATION)
                return;
 
@@ -1018,8 +1042,9 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_update_tkip_key);
 
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf,
-                               u8 sta_id)
+                          struct iwl_rxon_context *ctx,
+                          struct ieee80211_key_conf *keyconf,
+                          u8 sta_id)
 {
        unsigned long flags;
        u16 key_flags;
@@ -1028,7 +1053,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
 
        lockdep_assert_held(&priv->mutex);
 
-       priv->key_mapping_key--;
+       ctx->key_mapping_keys--;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
@@ -1080,26 +1105,26 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_remove_dynamic_key);
 
-int iwl_set_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf, u8 sta_id)
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                       struct ieee80211_key_conf *keyconf, u8 sta_id)
 {
        int ret;
 
        lockdep_assert_held(&priv->mutex);
 
-       priv->key_mapping_key++;
+       ctx->key_mapping_keys++;
        keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
        switch (keyconf->cipher) {
        case WLAN_CIPHER_SUITE_CCMP:
-               ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
+               ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
        case WLAN_CIPHER_SUITE_TKIP:
-               ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
+               ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
-               ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
+               ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
        default:
                IWL_ERR(priv,
@@ -1149,16 +1174,16 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
  * RXON flags are updated and when LQ command is updated.
  */
 static bool is_lq_table_valid(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
                              struct iwl_link_quality_cmd *lq)
 {
        int i;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
 
-       if (ht_conf->is_ht)
+       if (ctx->ht.enabled)
                return true;
 
        IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
-                      priv->active_rxon.channel);
+                      ctx->active.channel);
        for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
                if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
                        IWL_DEBUG_INFO(priv,
@@ -1180,7 +1205,7 @@ static bool is_lq_table_valid(struct iwl_priv *priv,
  * this case to clear the state indicating that station creation is in
  * progress.
  */
-int iwl_send_lq_cmd(struct iwl_priv *priv,
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    struct iwl_link_quality_cmd *lq, u8 flags, bool init)
 {
        int ret = 0;
@@ -1199,7 +1224,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
        iwl_dump_lq_cmd(priv, lq);
        BUG_ON(init && (cmd.flags & CMD_ASYNC));
 
-       if (is_lq_table_valid(priv, lq))
+       if (is_lq_table_valid(priv, ctx, lq))
                ret = iwl_send_cmd(priv, &cmd);
        else
                ret = -EINVAL;
@@ -1225,14 +1250,15 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
  * and marks it driver active, so that it will be restored to the
  * device at the next best time.
  */
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
+int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           bool init_lq)
 {
        struct iwl_link_quality_cmd *link_cmd;
        unsigned long flags;
        u8 sta_id;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL);
+       sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare broadcast station\n");
                spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -1267,11 +1293,12 @@ EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
  * Only used by iwlagn. Placed here to have all bcast station management
  * code together.
  */
-int iwl_update_bcast_station(struct iwl_priv *priv)
+static int iwl_update_bcast_station(struct iwl_priv *priv,
+                                   struct iwl_rxon_context *ctx)
 {
        unsigned long flags;
        struct iwl_link_quality_cmd *link_cmd;
-       u8 sta_id = priv->hw_params.bcast_sta_id;
+       u8 sta_id = ctx->bcast_sta_id;
 
        link_cmd = iwl_sta_alloc_lq(priv, sta_id);
        if (!link_cmd) {
@@ -1289,9 +1316,23 @@ int iwl_update_bcast_station(struct iwl_priv *priv)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
 
-void iwl_dealloc_bcast_station(struct iwl_priv *priv)
+int iwl_update_bcast_stations(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret = 0;
+
+       for_each_context(priv, ctx) {
+               ret = iwl_update_bcast_station(priv, ctx);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iwl_update_bcast_stations);
+
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
 {
        unsigned long flags;
        int i;
@@ -1309,7 +1350,7 @@ void iwl_dealloc_bcast_station(struct iwl_priv *priv)
        }
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
-EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
+EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations);
 
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
index d38a350ba0bd46a7d98e09810346243dea2be528..56bad3f60d8131c74d3874472370e1ca0d241bdb 100644 (file)
 
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
                               struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            struct ieee80211_key_conf *key);
-int iwl_restore_default_wep_keys(struct iwl_priv *priv);
-int iwl_set_dynamic_key(struct iwl_priv *priv,
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx);
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                        struct ieee80211_key_conf *key, u8 sta_id);
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
+int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           struct ieee80211_key_conf *key, u8 sta_id);
 void iwl_update_tkip_key(struct iwl_priv *priv,
-                       struct ieee80211_key_conf *keyconf,
-                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
-
-void iwl_restore_stations(struct iwl_priv *priv);
-void iwl_clear_ucode_stations(struct iwl_priv *priv);
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
-void iwl_dealloc_bcast_station(struct iwl_priv *priv);
-int iwl_update_bcast_station(struct iwl_priv *priv);
+                        struct iwl_rxon_context *ctx,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
+
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx);
+int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           bool init_lq);
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
+int iwl_update_bcast_stations(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
-                         u8 *sta_id_r);
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
-                                 bool is_ap,
-                                 struct ieee80211_sta_ht_cap *ht_info,
-                                 u8 *sta_id_r);
+int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                         const u8 *addr, bool init_rs, u8 *sta_id_r);
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r);
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
 int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -94,20 +99,25 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
 {
        unsigned long flags;
+       struct iwl_rxon_context *ctx;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        memset(priv->stations, 0, sizeof(priv->stations));
        priv->num_stations = 0;
 
-       /*
-        * Remove all key information that is not stored as part of station
-        * information since mac80211 may not have had a
-        * chance to remove all the keys. When device is reconfigured by
-        * mac80211 after an error all keys will be reconfigured.
-        */
        priv->ucode_key_table = 0;
-       priv->key_mapping_key = 0;
-       memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
+
+       for_each_context(priv, ctx) {
+               /*
+                * Remove all key information that is not stored as part
+                * of station information since mac80211 may not have had
+                * a chance to remove all the keys. When device is
+                * reconfigured by mac80211 after an error all keys will
+                * be reconfigured.
+                */
+               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
+               ctx->key_mapping_keys = 0;
+       }
 
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
@@ -123,6 +133,7 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
 /**
  * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
  * @priv: iwl priv
+ * @context: the current context
  * @sta: mac80211 station
  *
  * In certain circumstances mac80211 passes a station pointer
@@ -131,12 +142,13 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
  * inline wraps that pattern.
  */
 static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
+                                         struct iwl_rxon_context *context,
                                          struct ieee80211_sta *sta)
 {
        int sta_id;
 
        if (!sta)
-               return priv->hw_params.bcast_sta_id;
+               return context->bcast_sta_id;
 
        sta_id = iwl_sta_id(sta);
 
index c308dab14673d7d4d3b27315a13c49bcfa0b5d66..347d3dc6a01549632227ae8f1acd5ae84a1c50e0 100644 (file)
@@ -134,7 +134,7 @@ EXPORT_SYMBOL(iwl_tx_queue_free);
  */
 void iwl_cmd_queue_free(struct iwl_priv *priv)
 {
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct device *dev = &priv->pci_dev->dev;
        int i;
@@ -271,7 +271,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
 
        /* Driver private data, only for Tx (not command) queues,
         * not shared with device. */
-       if (id != IWL_CMD_QUEUE_NUM) {
+       if (id != priv->cmd_queue) {
                txq->txb = kzalloc(sizeof(txq->txb[0]) *
                                   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
                if (!txq->txb) {
@@ -314,13 +314,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 
        /*
         * Alloc buffer array for commands (Tx or other types of commands).
-        * For the command queue (#4), allocate command space + one big
+        * For the command queue (#4/#9), allocate command space + one big
         * command for scan, since scan command is very huge; the system will
         * not have two scans at the same time, so only one is needed.
         * For normal Tx queues (all other queues), no super-size command
         * space is needed.
         */
-       if (txq_id == IWL_CMD_QUEUE_NUM)
+       if (txq_id == priv->cmd_queue)
                actual_slots++;
 
        txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
@@ -355,7 +355,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
         * need an swq_id so don't set one to catch errors, all others can
         * be set up to the identity mapping.
         */
-       if (txq_id != IWL_CMD_QUEUE_NUM)
+       if (txq_id != priv->cmd_queue)
                txq->swq_id = txq_id;
 
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -385,7 +385,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 {
        int actual_slots = slots_num;
 
-       if (txq_id == IWL_CMD_QUEUE_NUM)
+       if (txq_id == priv->cmd_queue)
                actual_slots++;
 
        memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
@@ -413,7 +413,7 @@ EXPORT_SYMBOL(iwl_tx_queue_reset);
  */
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
@@ -483,7 +483,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
         * information */
 
        out_cmd->hdr.flags = 0;
-       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
                        INDEX_TO_SEQ(q->write_ptr));
        if (cmd->flags & CMD_SIZE_HUGE)
                out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
@@ -500,15 +500,15 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                                get_cmd_string(out_cmd->hdr.cmd),
                                out_cmd->hdr.cmd,
                                le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
-                               break;
+                               q->write_ptr, idx, priv->cmd_queue);
+               break;
        default:
                IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
                                "%d bytes at %d[%d]:%d\n",
                                get_cmd_string(out_cmd->hdr.cmd),
                                out_cmd->hdr.cmd,
                                le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+                               q->write_ptr, idx, priv->cmd_queue);
        }
 #endif
        txq->need_update = 1;
@@ -587,16 +587,16 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
 
        /* If a Tx command is being handled and it isn't in the actual
         * command queue then there a command routing bug has been introduced
         * in the queue management code. */
-       if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
-                "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
-                 txq_id, sequence,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+       if (WARN(txq_id != priv->cmd_queue,
+                "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
+                 txq_id, priv->cmd_queue, sequence,
+                 priv->txq[priv->cmd_queue].q.read_ptr,
+                 priv->txq[priv->cmd_queue].q.write_ptr)) {
                iwl_print_hex_error(priv, pkt, 32);
                return;
        }
index 94d7e6e1323d209da6a0addabcbe50fd264b9307..68e624afb9879d28554e522e8857137aea5ff212 100644 (file)
@@ -144,7 +144,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -317,7 +317,7 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                int left)
 {
 
-       if (!iwl_is_associated(priv) || !priv->ibss_beacon)
+       if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->ibss_beacon)
                return 0;
 
        if (priv->ibss_beacon->len > left)
@@ -343,7 +343,8 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
                return -ENOMEM;
        }
 
-       rate = iwl_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv,
+                               &priv->contexts[IWL_RXON_CTX_BSS]);
 
        frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
 
@@ -512,7 +513,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(
+                       priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                       info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -542,6 +545,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
        txq->txb[q->write_ptr].skb = skb;
+       txq->txb[q->write_ptr].ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[idx];
@@ -683,11 +687,12 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        int rc;
        int spectrum_resp_status;
        int duration = le16_to_cpu(params->duration);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                add_time = iwl_usecs_to_beacons(priv,
                        le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
-                       le16_to_cpu(priv->rxon_timing.beacon_interval));
+                       le16_to_cpu(ctx->timing.beacon_interval));
 
        memset(&spectrum, 0, sizeof(spectrum));
 
@@ -698,18 +703,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        cmd.len = sizeof(spectrum);
        spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                spectrum.start_time =
                        iwl_add_beacon_time(priv,
                                priv->_3945.last_beacon_time, add_time,
-                               le16_to_cpu(priv->rxon_timing.beacon_interval));
+                               le16_to_cpu(ctx->timing.beacon_interval));
        else
                spectrum.start_time = 0;
 
        spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
        spectrum.channels[0].channel = params->channel;
        spectrum.channels[0].type = type;
-       if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+       if (ctx->active.flags & RXON_FLG_BAND_24G_MSK)
                spectrum.flags |= RXON_FLG_BAND_24G_MSK |
                    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
 
@@ -798,7 +803,8 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       beacon = ieee80211_beacon_get(priv->hw,
+                       priv->contexts[IWL_RXON_CTX_BSS].vif);
 
        if (!beacon) {
                IWL_ERR(priv, "update beacon failed\n");
@@ -2468,6 +2474,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 {
        int thermal_spin = 0;
        u32 rfkill;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
@@ -2525,22 +2532,22 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 
        iwl_power_update_mode(priv, true);
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                struct iwl3945_rxon_cmd *active_rxon =
-                               (struct iwl3945_rxon_cmd *)(&priv->active_rxon);
+                               (struct iwl3945_rxon_cmd *)(&ctx->active);
 
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, NULL);
+               iwl_connection_init_rx_config(priv, ctx);
        }
 
        /* Configure Bluetooth device coexistence support */
        priv->cfg->ops->hcmd->send_bt_config(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        iwl3945_reg_txpower_periodic(priv);
 
@@ -2571,9 +2578,14 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
+       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+        * to prevent rearm timer */
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
+
        /* Station information will now be cleared in device */
-       iwl_clear_ucode_stations(priv);
-       iwl_dealloc_bcast_station(priv);
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
@@ -2655,7 +2667,8 @@ static int __iwl3945_up(struct iwl_priv *priv)
 {
        int rc, i;
 
-       rc = iwl_alloc_bcast_station(priv, false);
+       rc = iwl_alloc_bcast_station(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    false);
        if (rc)
                return rc;
 
@@ -2878,7 +2891,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
        scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                u16 interval = 0;
                u32 extra;
                u32 suspend_time = 100;
@@ -2939,7 +2952,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        /* We don't build a direct scan probe request; the uCode will do
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        /* flags + rate selection */
@@ -3037,8 +3050,10 @@ static void iwl3945_bg_restart(struct work_struct *data)
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               struct iwl_rxon_context *ctx;
                mutex_lock(&priv->mutex);
-               priv->vif = NULL;
+               for_each_context(priv, ctx)
+                       ctx->vif = NULL;
                priv->is_open = 0;
                mutex_unlock(&priv->mutex);
                iwl3945_down(priv);
@@ -3072,6 +3087,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
        struct ieee80211_conf *conf = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (!vif || !priv->is_open)
                return;
@@ -3082,7 +3098,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
        }
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, ctx->active.bssid_addr);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -3091,34 +3107,34 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
-       rc = iwl_send_rxon_timing(priv, vif);
+       rc = iwl_send_rxon_timing(priv, ctx);
        if (rc)
                IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                            "Attempting to continue.\n");
 
-       priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
        if (vif->bss_conf.use_short_preamble)
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                if (vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
 
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -3255,44 +3271,45 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int rc = 0;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
-       if (!(iwl_is_associated(priv))) {
+       if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) {
 
                /* RXON - unassoc (to set timing command) */
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
 
                /* RXON Timing */
-               rc = iwl_send_rxon_timing(priv, vif);
+               rc = iwl_send_rxon_timing(priv, ctx);
                if (rc)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               priv->staging_rxon.assoc_id = 0;
+               ctx->staging.assoc_id = 0;
 
                if (vif->bss_conf.use_short_preamble)
-                       priv->staging_rxon.flags |=
+                       ctx->staging.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &=
+                       ctx->staging.flags &=
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-               if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+               if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                        if (vif->bss_conf.use_short_slot)
-                               priv->staging_rxon.flags |=
+                               ctx->staging.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
-                               priv->staging_rxon.flags &=
+                               ctx->staging.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3318,10 +3335,11 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       static_key = !iwl_is_associated(priv);
+       static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS);
 
        if (!static_key) {
-               sta_id = iwl_sta_id_or_broadcast(priv, sta);
+               sta_id = iwl_sta_id_or_broadcast(
+                               priv, &priv->contexts[IWL_RXON_CTX_BSS], sta);
                if (sta_id == IWL_INVALID_STATION)
                        return -EINVAL;
        }
@@ -3372,8 +3390,8 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
        sta_priv->common.sta_id = IWL_INVALID_STATION;
 
 
-       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
-                                    &sta_id);
+       ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    sta->addr, is_ap, sta, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
@@ -3400,6 +3418,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
 #define CHK(test, flag)        do { \
        if (*total_flags & (test))              \
@@ -3419,8 +3438,8 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       priv->staging_rxon.filter_flags &= ~filter_nand;
-       priv->staging_rxon.filter_flags |= filter_or;
+       ctx->staging.filter_flags &= ~filter_nand;
+       ctx->staging.filter_flags |= filter_or;
 
        /*
         * Committing directly here breaks for some reason,
@@ -3534,8 +3553,9 @@ static ssize_t show_flags(struct device *d,
                          struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+       return sprintf(buf, "0x%04X\n", ctx->active.flags);
 }
 
 static ssize_t store_flags(struct device *d,
@@ -3544,17 +3564,18 @@ static ssize_t store_flags(struct device *d,
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
        u32 flags = simple_strtoul(buf, NULL, 0);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+       if (le32_to_cpu(ctx->staging.flags) != flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",
                                       flags);
-                       priv->staging_rxon.flags = cpu_to_le32(flags);
-                       iwlcore_commit_rxon(priv);
+                       ctx->staging.flags = cpu_to_le32(flags);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3568,9 +3589,10 @@ static ssize_t show_filter_flags(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        return sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->active_rxon.filter_flags));
+               le32_to_cpu(ctx->active.filter_flags));
 }
 
 static ssize_t store_filter_flags(struct device *d,
@@ -3578,19 +3600,20 @@ static ssize_t store_filter_flags(struct device *d,
                                  const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 filter_flags = simple_strtoul(buf, NULL, 0);
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+       if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "
                                       "0x%04X\n", filter_flags);
-                       priv->staging_rxon.filter_flags =
+                       ctx->staging.filter_flags =
                                cpu_to_le32(filter_flags);
-                       iwlcore_commit_rxon(priv);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3638,8 +3661,9 @@ static ssize_t store_measurement(struct device *d,
                                 const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct ieee80211_measurement_params params = {
-               .channel = le16_to_cpu(priv->active_rxon.channel),
+               .channel = le16_to_cpu(ctx->active.channel),
                .start_time = cpu_to_le64(priv->_3945.last_tsf),
                .duration = cpu_to_le16(1),
        };
@@ -3811,8 +3835,6 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->start_internal_scan);
        cancel_work_sync(&priv->beacon_update);
-       if (priv->cfg->ops->lib->recover_from_tx_stall)
-               del_timer_sync(&priv->monitor_recover);
 }
 
 static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3933,8 +3955,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
        hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+               priv->contexts[IWL_RXON_CTX_BSS].interface_modes;
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3966,7 +3987,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
 static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int err = 0;
+       int err = 0, i;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3988,6 +4009,27 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv = hw->priv;
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
+       priv->cmd_queue = IWL39_CMD_QUEUE_NUM;
+
+       /* 3945 has only one valid context */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
        /*
         * Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan.
@@ -4123,7 +4165,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        }
 
        iwl_set_rxon_channel(priv,
-                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
+                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5],
+                            &priv->contexts[IWL_RXON_CTX_BSS]);
        iwl3945_setup_deferred_work(priv);
        iwl3945_setup_rx_handlers(priv);
        iwl_power_initialize(priv);
index 298ba79fc51b39b527732babb1a36aa33460a92a..92b486d46eb9fca3d7e53fa39102574156e4d24c 100644 (file)
@@ -601,6 +601,18 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 }
 
 
+static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          enum nl80211_iftype newtype)
+{
+       wiphy_debug(hw->wiphy,
+                   "%s (old type=%d, new type=%d, mac_addr=%pM)\n",
+                   __func__, vif->type, newtype, vif->addr);
+       hwsim_check_magic(vif);
+
+       return 0;
+}
+
 static void mac80211_hwsim_remove_interface(
        struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
@@ -1027,6 +1039,7 @@ static struct ieee80211_ops mac80211_hwsim_ops =
        .start = mac80211_hwsim_start,
        .stop = mac80211_hwsim_stop,
        .add_interface = mac80211_hwsim_add_interface,
+       .change_interface = mac80211_hwsim_change_interface,
        .remove_interface = mac80211_hwsim_remove_interface,
        .config = mac80211_hwsim_config,
        .configure_filter = mac80211_hwsim_configure_filter,
index 077baa86756b07db035799d319fa366abdd01490..b4772c1c6135c40fcad9859b6510eff0e1224182 100644 (file)
@@ -762,14 +762,17 @@ int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
        case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
        case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
                for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-                       if (bitrate_table[i].intersil_txratectrl == val)
+                       if (bitrate_table[i].intersil_txratectrl == val) {
+                               *bitrate = bitrate_table[i].bitrate * 100000;
                                break;
+                       }
 
-               if (i >= BITRATE_TABLE_SIZE)
+               if (i >= BITRATE_TABLE_SIZE) {
                        printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
                               priv->ndev->name, val);
+                       err = -EIO;
+               }
 
-               *bitrate = bitrate_table[i].bitrate * 100000;
                break;
        default:
                BUG();
index cf7be1eb612495b699dc2e0cdc8fe17650c26736..93505f93bf97711019e86bbe27f39f4f727bce01 100644 (file)
@@ -589,8 +589,15 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
 
        /* If the interface is running we try to find more about the
           current mode */
-       if (netif_running(dev))
-               err = orinoco_hw_get_act_bitrate(priv, &bitrate);
+       if (netif_running(dev)) {
+               int act_bitrate;
+               int lerr;
+
+               /* Ignore errors if we can't get the actual bitrate */
+               lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
+               if (!lerr)
+                       bitrate = act_bitrate;
+       }
 
        orinoco_unlock(priv, &flags);
 
index 60a930e45a8b16e0cee3b2cae628f6740f558836..e5f45cb2a7a2334d839560d7c6366227f83c0030 100644 (file)
@@ -49,6 +49,23 @@ config P54_SPI
 
          If you choose to build a module, it'll be called p54spi.
 
+config P54_SPI_DEFAULT_EEPROM
+       bool "Include fallback EEPROM blob"
+       depends on P54_SPI
+       default n
+       ---help---
+        Unlike the PCI or USB devices, the SPI variants don't have
+        a dedicated EEPROM chip to store all device specific values
+        for calibration, country and interface settings.
+
+        The driver will try to load the image "3826.eeprom", if the
+        file is put at the right place. (usually /lib/firmware.)
+
+        Only if this request fails, this option will provide a
+        backup set of generic values to get the device working.
+
+        Enabling this option adds about 4k to p54spi.
+
 config P54_LEDS
        bool
        depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON)
index 087bf0698a5af7aee75a8c47fac852fe4cd35fa1..156e57dbd2cfa858df969ab3e98c8476f173ee89 100644 (file)
 #include <linux/slab.h>
 
 #include "p54spi.h"
-#include "p54spi_eeprom.h"
 #include "p54.h"
 
 #include "lmac.h"
 
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
+#include "p54spi_eeprom.h"
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
+
 MODULE_FIRMWARE("3826.arm");
 MODULE_ALIAS("stlc45xx");
 
@@ -195,9 +198,11 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev)
 
        ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev);
        if (ret < 0) {
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
                dev_info(&priv->spi->dev, "loading default eeprom...\n");
                ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
                                       sizeof(p54spi_eeprom));
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
        } else {
                dev_info(&priv->spi->dev, "loading user eeprom...\n");
                ret = p54_parse_eeprom(dev, (void *) eeprom->data,
index ad595958b7df19f144a38671cc0424551aaba709..063248b350692f13b6948e63722e28b4b634434d 100644 (file)
@@ -930,8 +930,8 @@ static int __devinit p54u_probe(struct usb_interface *intf,
 #ifdef CONFIG_PM
                /* ISL3887 needs a full reset on resume */
                udev->reset_resume = 1;
+#endif /* CONFIG_PM */
                err = p54u_device_reset(dev);
-#endif
 
                priv->hw_type = P54U_3887;
                dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
index 34447d1ad80debfdc5f44948ae56b440771b49f2..8f67db487f57cb2b50a822483a41abe35c652635 100644 (file)
@@ -275,15 +275,15 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
 {
        int band = priv->hw->conf.channel->band;
 
-       if (priv->rxhw != 5)
+       if (priv->rxhw != 5) {
                return ((rssi * priv->rssical_db[band].mul) / 64 +
                         priv->rssical_db[band].add) / 4;
-       else
+       } else {
                /*
                 * TODO: find the correct formula
                 */
-               return ((rssi * priv->rssical_db[band].mul) / 64 +
-                        priv->rssical_db[band].add) / 4;
+               return rssi / 2 - 110;
+       }
 }
 
 /*
index 8e3fbdf4888972eb6d4dc2e22ba38da64edc2236..103c71164f109d05f7b87fc77b479ae856f7502d 100644 (file)
@@ -1007,12 +1007,11 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2400pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1096,7 +1095,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2400pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1112,24 +1111,24 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
-static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
+static void rt2400pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
-static void rt2400pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2400pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, CSR14, 0);
        } else {
                rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1488,8 +1487,10 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER);
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        return 0;
 }
index 1d174e42f11e2c6a13a4625f83c4570407d1e660..ab0507110e423b2cd2afbd79b50c1277f29a9661 100644 (file)
@@ -1161,12 +1161,11 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2500pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1249,7 +1248,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2500pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1265,24 +1264,24 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
-static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
+static void rt2500pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
-static void rt2500pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2500pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, CSR14, 0);
        } else {
                rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1802,12 +1801,16 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = DEFAULT_TXPOWER;
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = DEFAULT_TXPOWER;
+               }
        }
 
        return 0;
index baadf03a800e1692108d5529b93bc3dac14bbb73..db64df4267d8b77a7619374a341c40178f6f72fc 100644 (file)
@@ -1041,12 +1041,11 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2500usb_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txd = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -1129,7 +1128,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2500usb_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1197,6 +1196,14 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
+static void rt2500usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -1707,12 +1714,16 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = DEFAULT_TXPOWER;
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = DEFAULT_TXPOWER;
+               }
        }
 
        return 0;
@@ -1791,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .write_beacon           = rt2500usb_write_beacon,
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt2500usb_kill_tx_queue,
        .fill_rxdone            = rt2500usb_fill_rxdone,
        .config_shared_key      = rt2500usb_config_key,
        .config_pairwise_key    = rt2500usb_config_key,
index cf1f16bfcd5eaa50c790aeff49db85d4874a3e75..70a5cb86405b14b0589199700f137e43df771953 100644 (file)
@@ -1858,6 +1858,13 @@ struct mac_iveiv_entry {
 #define EEPROM_RSSI_A2_OFFSET2         FIELD16(0x00ff)
 #define EEPROM_RSSI_A2_LNA_A2          FIELD16(0xff00)
 
+/*
+ * EEPROM Maximum TX power values
+ */
+#define EEPROM_MAX_TX_POWER            0x0027
+#define EEPROM_MAX_TX_POWER_24GHZ      FIELD16(0x00ff)
+#define EEPROM_MAX_TX_POWER_5GHZ       FIELD16(0xff00)
+
 /*
  * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
  *     This is delta in 40MHZ.
@@ -1946,6 +1953,8 @@ struct mac_iveiv_entry {
  * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs
  * BW: Channel bandwidth 20MHz or 40 MHz
  * 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.
  */
 #define TXWI_W0_FRAG                   FIELD32(0x00000001)
 #define TXWI_W0_MIMO_PS                        FIELD32(0x00000002)
@@ -1969,7 +1978,9 @@ struct mac_iveiv_entry {
  * WIRELESS_CLI_ID: Client ID for WCID table access
  * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame
  * PACKETID: Will be latched into the TX_STA_FIFO register once the according
- *           frame was processed. 0: Don't report tx status for this frame.
+ *           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.
  */
 #define TXWI_W1_ACK                    FIELD32(0x00000001)
 #define TXWI_W1_NSEQ                   FIELD32(0x00000002)
index 6a0cb2d924d84008ff454ababcde150f2051691a..27a6e225083c94211f3a7109e595df74cfac9d4a 100644 (file)
@@ -255,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2800_mcu_request);
 
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
+{
+       unsigned int i = 0;
+       u32 reg;
+
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+               if (reg && reg != ~0)
+                       return 0;
+               msleep(1);
+       }
+
+       ERROR(rt2x00dev, "Unstable hardware.\n");
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);
+
 int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
 {
        unsigned int i;
@@ -368,19 +385,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
        u32 reg;
 
        /*
-        * Wait for stable hardware.
+        * If driver doesn't wake up firmware here,
+        * rt2800_load_firmware will hang forever when interface is up again.
         */
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-               if (reg && reg != ~0)
-                       break;
-               msleep(1);
-       }
+       rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
 
-       if (i == REGISTER_BUSY_COUNT) {
-               ERROR(rt2x00dev, "Unstable hardware.\n");
+       /*
+        * Wait for stable hardware.
+        */
+       if (rt2800_wait_csr_ready(rt2x00dev))
                return -EBUSY;
-       }
 
        if (rt2x00_is_pci(rt2x00dev))
                rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
@@ -469,7 +483,7 @@ 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->queue + 1);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1);
        rt2x00_desc_write(txwi, 1, word);
 
        /*
@@ -573,6 +587,49 @@ void rt2800_process_rxwi(struct queue_entry *entry,
 }
 EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
 
+static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+       __le32 *txwi;
+       u32 word;
+       int wcid, ack, pid;
+       int tx_wcid, tx_ack, tx_pid;
+
+       wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+       ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+       pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
+       /*
+        * This frames has returned with an IO error,
+        * so the status report is not intended for this
+        * frame.
+        */
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
+               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+               return false;
+       }
+
+       /*
+        * Validate if this TX status report is intended for
+        * this entry by comparing the WCID/ACK/PID fields.
+        */
+       txwi = rt2800_drv_get_txwi(entry);
+
+       rt2x00_desc_read(txwi, 1, &word);
+       tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+       tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
+       tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+       if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
+               WARNING(entry->queue->rt2x00dev,
+                       "TX status report missed for queue %d entry %d\n",
+               entry->queue->qid, entry->entry_idx);
+               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+               return false;
+       }
+
+       return true;
+}
+
 void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
@@ -581,8 +638,8 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
        struct txdone_entry_desc txdesc;
        u32 word;
        u32 reg;
-       int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
        u16 mcs, real_mcs;
+       u8 pid;
        int i;
 
        /*
@@ -599,18 +656,15 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
                if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
                        break;
 
-               wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-               ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
-               pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-
                /*
                 * Skip this entry when it contains an invalid
                 * queue identication number.
                 */
-               if (pid <= 0 || pid > QID_RX)
+               pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
+               if (pid >= QID_RX)
                        continue;
 
-               queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
+               queue = rt2x00queue_get_queue(rt2x00dev, pid);
                if (unlikely(!queue))
                        continue;
 
@@ -619,38 +673,24 @@ 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 (!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+                       if (rt2800_txdone_entry_check(entry, reg))
                                break;
-
-                       rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
                }
 
                if (!entry || rt2x00queue_empty(queue))
                        break;
 
-               /*
-                * Check if we got a match by looking at WCID/ACK/PID
-                * fields
-                */
-               txwi = rt2800_drv_get_txwi(entry);
-
-               rt2x00_desc_read(txwi, 1, &word);
-               tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-               tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
-               tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
-               if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
-                       WARNING(rt2x00dev, "invalid TX_STA_FIFO content");
 
                /*
                 * 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);
-               mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
                real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
 
                /*
@@ -1095,19 +1135,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
        }
 
        if (flags & CONFIG_UPDATE_MAC) {
-               reg = le32_to_cpu(conf->mac[1]);
-               rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
-               conf->mac[1] = cpu_to_le32(reg);
+               if (!is_zero_ether_addr((const u8 *)conf->mac)) {
+                       reg = le32_to_cpu(conf->mac[1]);
+                       rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
+                       conf->mac[1] = cpu_to_le32(reg);
+               }
 
                rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
                                              conf->mac, sizeof(conf->mac));
        }
 
        if (flags & CONFIG_UPDATE_BSSID) {
-               reg = le32_to_cpu(conf->bssid[1]);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
-               conf->bssid[1] = cpu_to_le32(reg);
+               if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
+                       reg = le32_to_cpu(conf->bssid[1]);
+                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
+                       conf->bssid[1] = cpu_to_le32(reg);
+               }
 
                rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
                                              conf->bssid, sizeof(conf->bssid));
@@ -1240,27 +1284,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
                 * double meaning, and we should set a 7DBm boost flag.
                 */
                rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
-                                  (info->tx_power1 >= 0));
+                                  (info->default_power1 >= 0));
 
-               if (info->tx_power1 < 0)
-                       info->tx_power1 += 7;
+               if (info->default_power1 < 0)
+                       info->default_power1 += 7;
 
-               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A,
-                                  TXPOWER_A_TO_DEV(info->tx_power1));
+               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1);
 
                rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
-                                  (info->tx_power2 >= 0));
+                                  (info->default_power2 >= 0));
 
-               if (info->tx_power2 < 0)
-                       info->tx_power2 += 7;
+               if (info->default_power2 < 0)
+                       info->default_power2 += 7;
 
-               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
-                                  TXPOWER_A_TO_DEV(info->tx_power2));
+               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2);
        } else {
-               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power1));
-               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power2));
+               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1);
+               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2);
        }
 
        rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
@@ -1300,13 +1340,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
-                         TXPOWER_G_TO_DEV(info->tx_power1));
+       rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1);
        rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
-                         TXPOWER_G_TO_DEV(info->tx_power2));
+       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2);
        rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
@@ -1330,10 +1368,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp;
 
+       if (rf->channel <= 14) {
+               info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
+               info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2);
+       } else {
+               info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1);
+               info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
+       }
+
        if (rt2x00_rf(rt2x00dev, RF2020) ||
            rt2x00_rf(rt2x00dev, RF3020) ||
            rt2x00_rf(rt2x00dev, RF3021) ||
-           rt2x00_rf(rt2x00dev, RF3022))
+           rt2x00_rf(rt2x00dev, RF3022) ||
+           rt2x00_rf(rt2x00dev, RF3052))
                rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
        else
                rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -1656,7 +1703,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner);
 /*
  * Initialization functions.
  */
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
        u16 eeprom;
@@ -2026,7 +2073,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_registers);
 
 static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
 {
@@ -2069,7 +2115,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
        return -EACCES;
 }
 
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 {
        unsigned int i;
        u16 eeprom;
@@ -2164,7 +2210,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_bbp);
 
 static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
                                bool bw40, u8 rfcsr24, u8 filter_target)
@@ -2226,7 +2271,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
        return rfcsr24;
 }
 
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
        u8 rfcsr;
        u8 bbp;
@@ -2480,7 +2525,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
+
+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       u16 word;
+
+       /*
+        * Initialize all registers.
+        */
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
+                    rt2800_init_registers(rt2x00dev) ||
+                    rt2800_init_bbp(rt2x00dev) ||
+                    rt2800_init_rfcsr(rt2x00dev)))
+               return -EIO;
+
+       /*
+        * Send signal to firmware during boot time.
+        */
+       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+
+       if (rt2x00_is_usb(rt2x00dev) &&
+           (rt2x00_rt(rt2x00dev, RT3070) ||
+            rt2x00_rt(rt2x00dev, RT3071) ||
+            rt2x00_rt(rt2x00dev, RT3572))) {
+               udelay(200);
+               rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
+               udelay(10);
+       }
+
+       /*
+        * Enable RX.
+        */
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       udelay(50);
+
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       /*
+        * Initialize LED control
+        */
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_enable_radio);
+
+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+       /* Wait for DMA, ignore error */
+       rt2800_wait_wpdma_ready(rt2x00dev);
+
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 0);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+}
+EXPORT_SYMBOL_GPL(rt2800_disable_radio);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
 {
@@ -2636,6 +2774,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                                   default_lna_gain);
        rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
 
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word);
+       if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff)
+               rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER);
+       if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff)
+               rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER);
+       rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_validate_eeprom);
@@ -2875,9 +3020,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
        struct hw_mode_spec *spec = &rt2x00dev->spec;
        struct channel_info *info;
-       char *tx_power1;
-       char *tx_power2;
+       char *default_power1;
+       char *default_power2;
        unsigned int i;
+       unsigned short max_power;
        u16 eeprom;
 
        /*
@@ -2991,21 +3137,26 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        spec->channels_info = info;
 
-       tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
-       tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom);
+       max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ);
+       default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+       default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
 
        for (i = 0; i < 14; i++) {
-               info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
-               info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
+               info[i].max_power = max_power;
+               info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]);
+               info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]);
        }
 
        if (spec->num_channels > 14) {
-               tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
-               tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
+               max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ);
+               default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
+               default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
 
                for (i = 14; i < spec->num_channels; i++) {
-                       info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
-                       info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
+                       info[i].max_power = max_power;
+                       info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]);
+                       info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]);
                }
        }
 
index 3b572c63382d85309cdf519be77274298a0dae8b..986229c06c19ba02e0c6d9dc7633a7fa8f148113 100644 (file)
@@ -140,6 +140,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1);
 
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev);
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+
 int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
                          const u8 *data, const size_t len);
 int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
@@ -176,10 +179,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count);
 
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
-int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
 void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
index 4390f2b74b2e71ef997fd74382652638ce33a256..2bcb1507e3ac57289e536a8646f34b24b7818eec 100644 (file)
@@ -196,8 +196,6 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
-
        /*
         * enable Host program ram write selection
         */
@@ -399,78 +397,18 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
 
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       u32 reg;
-       u16 word;
-
-       /*
-        * Initialize all registers.
-        */
        if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800pci_init_queues(rt2x00dev) ||
-                    rt2800_init_registers(rt2x00dev) ||
-                    rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800_init_bbp(rt2x00dev) ||
-                    rt2800_init_rfcsr(rt2x00dev)))
+                    rt2800pci_init_queues(rt2x00dev)))
                return -EIO;
 
-       /*
-        * Send signal to firmware during boot time.
-        */
-       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
-       /*
-        * Enable RX.
-        */
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       /*
-        * Initialize LED control
-        */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       return 0;
+       return rt2800_enable_radio(rt2x00dev);
 }
 
 static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
-       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
-       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+       rt2800_disable_radio(rt2x00dev);
 
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
 
@@ -486,9 +424,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
-       /* Wait for DMA, ignore error */
-       rt2800_wait_wpdma_ready(rt2x00dev);
 }
 
 static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -571,12 +506,11 @@ static __le32 *rt2800pci_get_txwi(struct queue_entry *entry)
        return (__le32 *) entry->skb->data;
 }
 
-static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2800pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -596,7 +530,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 0, word);
 
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len);
+       rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len);
        rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
                           !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BURST,
@@ -627,41 +561,35 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
  * TX data initialization
  */
-static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue_idx)
+static void rt2800pci_kick_tx_queue(struct data_queue *queue)
 {
-       struct data_queue *queue;
-       unsigned int idx, qidx = 0;
-
-       if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
-               return;
-
-       queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
-       idx = queue->index[Q_INDEX];
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+       unsigned int qidx = 0;
 
-       if (queue_idx == QID_MGMT)
+       if (queue->qid == QID_MGMT)
                qidx = 5;
        else
-               qidx = queue_idx;
+               qidx = queue->qid;
 
-       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
 }
 
-static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2800pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
                return;
        }
 
        rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
        rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
 }
 
index 9ad28be294ebb95d8049edfb54dd0b5ce6a9776b..3dff56ec195abaa60e9500611a6a020da2dc199f 100644 (file)
@@ -101,19 +101,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
        msleep(10);
        rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
-       /*
-        * Send signal to firmware during boot time.
-        */
-       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
-       if (rt2x00_rt(rt2x00dev, RT3070) ||
-           rt2x00_rt(rt2x00dev, RT3071) ||
-           rt2x00_rt(rt2x00dev, RT3572)) {
-               udelay(200);
-               rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
-               udelay(10);
-       }
-
        return 0;
 }
 
@@ -135,26 +122,18 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
 static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
-       int i;
 
        /*
         * Wait until BBP and RF are ready.
         */
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-               if (reg && reg != ~0)
-                       break;
-               msleep(1);
-       }
-
-       if (i == REGISTER_BUSY_COUNT) {
-               ERROR(rt2x00dev, "Unstable hardware.\n");
+       if (rt2800_wait_csr_ready(rt2x00dev))
                return -EBUSY;
-       }
 
        rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
 
+       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
        rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
@@ -173,30 +152,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
-       u16 word;
 
-       /*
-        * Initialize all registers.
-        */
-       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800_init_registers(rt2x00dev) ||
-                    rt2800_init_bbp(rt2x00dev) ||
-                    rt2800_init_rfcsr(rt2x00dev)))
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
                return -EIO;
 
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       udelay(50);
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-
        rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
        rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
@@ -211,45 +170,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
        rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
 
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       /*
-        * Initialize LED control
-        */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       return 0;
+       return rt2800_enable_radio(rt2x00dev);
 }
 
 static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       u32 reg;
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
-       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
-       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
-
-       /* Wait for DMA, ignore error */
-       rt2800_wait_wpdma_ready(rt2x00dev);
-
+       rt2800_disable_radio(rt2x00dev);
        rt2x00usb_disable_radio(rt2x00dev);
 }
 
@@ -329,12 +255,11 @@ static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
                return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
 }
 
-static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2800usb_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txi = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txi = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -342,7 +267,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         */
        rt2x00_desc_read(txi, 0, &word);
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-                          skb->len - TXINFO_DESC_SIZE);
+                          entry->skb->len - TXINFO_DESC_SIZE);
        rt2x00_set_field32(&word, TXINFO_W0_WIV,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -410,6 +335,14 @@ static void rt2800usb_work_txdone(struct work_struct *work)
        }
 }
 
+static void rt2800usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -608,7 +541,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .write_beacon           = rt2800_write_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt2800usb_kill_tx_queue,
        .fill_rxdone            = rt2800usb_fill_rxdone,
        .config_shared_key      = rt2800_config_shared_key,
        .config_pairwise_key    = rt2800_config_pairwise_key,
index 8c65244a847a44c798a829aca48bc38e8c64abbe..0ae942cb66df4d55c5ab3d056f975749a670bd70 100644 (file)
@@ -213,8 +213,9 @@ struct channel_info {
        unsigned int flags;
 #define GEOGRAPHY_ALLOWED      0x00000001
 
-       short tx_power1;
-       short tx_power2;
+       short max_power;
+       short default_power1;
+       short default_power2;
 };
 
 /*
@@ -559,18 +560,15 @@ struct rt2x00lib_ops {
        /*
         * TX control handlers
         */
-       void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
-                              struct sk_buff *skb,
+       void (*write_tx_desc) (struct queue_entry *entry,
                               struct txentry_desc *txdesc);
        void (*write_tx_data) (struct queue_entry *entry,
                               struct txentry_desc *txdesc);
        void (*write_beacon) (struct queue_entry *entry,
                              struct txentry_desc *txdesc);
        int (*get_tx_data_len) (struct queue_entry *entry);
-       void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
-                              const enum data_queue_qid queue);
-       void (*kill_tx_queue) (struct rt2x00_dev *rt2x00dev,
-                              const enum data_queue_qid queue);
+       void (*kick_tx_queue) (struct data_queue *queue);
+       void (*kill_tx_queue) (struct data_queue *queue);
 
        /*
         * RX control handlers
@@ -1072,6 +1070,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmadone(struct queue_entry *entry);
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc);
 void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
index 2d018ceffc54574651f04bdc28bef571488f3f82..b8cf45c4e9f53ccf3ec250700b25eed71901a991 100644 (file)
@@ -338,7 +338,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
                return -ENOMEM;
 
        temp = data +
-           sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n");
+           sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
 
        queue_for_each(intf->rt2x00dev, queue) {
                spin_lock_irqsave(&queue->lock, irqflags);
@@ -346,8 +346,8 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
                temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
                                queue->count, queue->limit, queue->length,
                                queue->index[Q_INDEX],
-                               queue->index[Q_INDEX_DONE],
-                               queue->index[Q_INDEX_CRYPTO]);
+                               queue->index[Q_INDEX_DMA_DONE],
+                               queue->index[Q_INDEX_DONE]);
 
                spin_unlock_irqrestore(&queue->lock, irqflags);
        }
@@ -481,6 +481,9 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,        \
        if (index >= debug->__name.word_count)                  \
                return -EINVAL;                                 \
                                                                \
+       if (length > sizeof(line))                              \
+               return -EINVAL;                                 \
+                                                               \
        if (copy_from_user(line, buf, length))                  \
                return -EFAULT;                                 \
                                                                \
index e692608bee8ba285416363713f1cc46637baaaec..053fdd3bd7206c56836a7aa73aed12e155edd026 100644 (file)
@@ -251,6 +251,12 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
 
+void rt2x00lib_dmadone(struct queue_entry *entry)
+{
+       rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc)
 {
@@ -711,7 +717,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
        for (i = 0; i < spec->num_channels; i++) {
                rt2x00lib_channel(&channels[i],
                                  spec->channels[i].channel,
-                                 spec->channels_info[i].tx_power1, i);
+                                 spec->channels_info[i].max_power, i);
        }
 
        /*
index 480d33a3ce422a1276fb7dc396cc394b9e2a2eb3..eede99939db917936462a3e7372b5bb010413541 100644 (file)
@@ -312,7 +312,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        /*
         * Initialize information from queue
         */
-       txdesc->queue = entry->queue->qid;
+       txdesc->qid = entry->queue->qid;
        txdesc->cw_min = entry->queue->cw_min;
        txdesc->cw_max = entry->queue->cw_max;
        txdesc->aifs = entry->queue->aifs;
@@ -449,15 +449,14 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
                                            struct txentry_desc *txdesc)
 {
        struct data_queue *queue = entry->queue;
-       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
 
-       rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc);
 
        /*
         * All processing on the frame has been completed, this means
         * it is now ready to be dumped to userspace through debugfs.
         */
-       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+       rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb);
 }
 
 static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -477,7 +476,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
         */
        if (rt2x00queue_threshold(queue) ||
            !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
-               rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
+               rt2x00dev->ops->lib->kick_tx_queue(queue);
 }
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -591,7 +590,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        intf->beacon->skb = NULL;
 
        if (!enable_beacon) {
-               rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
+               rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
                mutex_unlock(&intf->beacon_skb_mutex);
                return 0;
        }
@@ -626,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        return 0;
 }
 
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry))
+{
+       unsigned long irqflags;
+       unsigned int index_start;
+       unsigned int index_end;
+       unsigned int i;
+
+       if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
+               ERROR(queue->rt2x00dev,
+                     "Entry requested from invalid index range (%d - %d)\n",
+                     start, end);
+               return;
+       }
+
+       /*
+        * Only protect the range we are going to loop over,
+        * if during our loop a extra entry is set to pending
+        * it should not be kicked during this run, since it
+        * is part of another TX operation.
+        */
+       spin_lock_irqsave(&queue->lock, irqflags);
+       index_start = queue->index[start];
+       index_end = queue->index[end];
+       spin_unlock_irqrestore(&queue->lock, irqflags);
+
+       /*
+        * Start from the TX done pointer, this guarentees that we will
+        * send out all frames in the correct order.
+        */
+       if (index_start < index_end) {
+               for (i = index_start; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       } else {
+               for (i = index_start; i < queue->limit; i++)
+                       fn(&queue->entries[i]);
+
+               for (i = 0; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
+
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
                                         const enum data_queue_qid queue)
 {
@@ -687,13 +731,13 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
        if (queue->index[index] >= queue->limit)
                queue->index[index] = 0;
 
+       queue->last_action[index] = jiffies;
+
        if (index == Q_INDEX) {
                queue->length++;
-               queue->last_index = jiffies;
        } else if (index == Q_INDEX_DONE) {
                queue->length--;
                queue->count++;
-               queue->last_index_done = jiffies;
        }
 
        spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -702,14 +746,17 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
 static void rt2x00queue_reset(struct data_queue *queue)
 {
        unsigned long irqflags;
+       unsigned int i;
 
        spin_lock_irqsave(&queue->lock, irqflags);
 
        queue->count = 0;
        queue->length = 0;
-       queue->last_index = jiffies;
-       queue->last_index_done = jiffies;
-       memset(queue->index, 0, sizeof(queue->index));
+
+       for (i = 0; i < Q_INDEX_MAX; i++) {
+               queue->index[i] = 0;
+               queue->last_action[i] = jiffies;
+       }
 
        spin_unlock_irqrestore(&queue->lock, irqflags);
 }
@@ -719,7 +766,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
 
        txall_queue_for_each(rt2x00dev, queue)
-               rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid);
+               rt2x00dev->ops->lib->kill_tx_queue(queue);
 }
 
 void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
index 2d3bf843735ffd87a8616997a893f2a3729e5a0b..d81d85f3486611cb79b18571694727c9616d7885 100644 (file)
@@ -296,7 +296,7 @@ enum txentry_desc_flags {
  * Summary of information for the frame descriptor before sending a TX frame.
  *
  * @flags: Descriptor flags (See &enum queue_entry_flags).
- * @queue: Queue identification (See &enum data_queue_qid).
+ * @qid: Queue identification (See &enum data_queue_qid).
  * @length: Length of the entire frame.
  * @header_length: Length of 802.11 header.
  * @length_high: PLCP length high word.
@@ -322,7 +322,7 @@ enum txentry_desc_flags {
 struct txentry_desc {
        unsigned long flags;
 
-       enum data_queue_qid queue;
+       enum data_queue_qid qid;
 
        u16 length;
        u16 header_length;
@@ -360,9 +360,6 @@ struct txentry_desc {
  * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
  *     transfer (either TX or RX depending on the queue). The entry should
  *     only be touched after the device has signaled it is done with it.
- * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data
- *     encryption or decryption. The entry should only be touched after
- *     the device has signaled it is done with it.
  * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
  *     for the signal to start sending.
  * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
@@ -372,7 +369,6 @@ struct txentry_desc {
 enum queue_entry_flags {
        ENTRY_BCN_ASSIGNED,
        ENTRY_OWNER_DEVICE_DATA,
-       ENTRY_OWNER_DEVICE_CRYPTO,
        ENTRY_DATA_PENDING,
        ENTRY_DATA_IO_FAILED
 };
@@ -405,18 +401,18 @@ struct queue_entry {
  *
  * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
  *     owned by the hardware then the queue is considered to be full.
+ * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been
+ *     transfered to the hardware.
  * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
  *     the hardware and for which we need to run the txdone handler. If this
  *     entry is not owned by the hardware the queue is considered to be empty.
- * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription
- *     will be completed by the hardware next.
  * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
  *     of the index array.
  */
 enum queue_index {
        Q_INDEX,
+       Q_INDEX_DMA_DONE,
        Q_INDEX_DONE,
-       Q_INDEX_CRYPTO,
        Q_INDEX_MAX,
 };
 
@@ -452,13 +448,12 @@ struct data_queue {
        enum data_queue_qid qid;
 
        spinlock_t lock;
-       unsigned long last_index;
-       unsigned long last_index_done;
        unsigned int count;
        unsigned short limit;
        unsigned short threshold;
        unsigned short length;
        unsigned short index[Q_INDEX_MAX];
+       unsigned long last_action[Q_INDEX_MAX];
 
        unsigned short txop;
        unsigned short aifs;
@@ -570,6 +565,22 @@ struct data_queue_desc {
 #define txall_queue_for_each(__dev, __entry) \
        queue_loop(__entry, (__dev)->tx, queue_end(__dev))
 
+/**
+ * rt2x00queue_for_each_entry - Loop through all entries in the queue
+ * @queue: Pointer to @data_queue
+ * @start: &enum queue_index Pointer to start index
+ * @end: &enum queue_index Pointer to end index
+ * @fn: The function to call for each &struct queue_entry
+ *
+ * This will walk through all entries in the queue, in chronological
+ * order. This means it will start at the current @start pointer
+ * and will walk through the queue until it reaches the @end pointer.
+ */
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry));
+
 /**
  * rt2x00queue_empty - Check if the queue is empty.
  * @queue: Queue to check if empty.
@@ -607,12 +618,23 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
 }
 
 /**
- * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts
  * @queue: Queue to check.
  */
 static inline int rt2x00queue_timeout(struct data_queue *queue)
 {
-       return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+       return time_after(queue->last_action[Q_INDEX_DMA_DONE],
+                         queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+}
+
+/**
+ * rt2x00queue_timeout - Check if a timeout occured for DMA transfers
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+{
+       return time_after(queue->last_action[Q_INDEX],
+                         queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
 }
 
 /**
index f76014f732cebabf591e1ea734efa3768e4d94c0..4c5ae3d456253ac0a1525fbe592ff9869c06bbc1 100644 (file)
@@ -208,10 +208,14 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 
-       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+       if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
+       /*
+        * Report the frame as DMA done
+        */
+       rt2x00lib_dmadone(entry);
+
        /*
         * Check if the frame was correctly uploaded
         */
@@ -222,112 +226,84 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
         * Schedule the delayed work for reading the TX status
         * from the device.
         */
-       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
 }
 
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        u32 length;
 
-       if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
-               /*
-                * USB devices cannot blindly pass the skb->len as the
-                * length of the data to usb_fill_bulk_urb. Pass the skb
-                * to the driver to determine what the length should be.
-                */
-               length = rt2x00dev->ops->lib->get_tx_data_len(entry);
-
-               usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                                 usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
-                                 entry->skb->data, length,
-                                 rt2x00usb_interrupt_txdone, entry);
-
-               usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
-       }
-}
-
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid)
-{
-       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
-       unsigned long irqflags;
-       unsigned int index;
-       unsigned int index_done;
-       unsigned int i;
+       if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+               return;
 
        /*
-        * Only protect the range we are going to loop over,
-        * if during our loop a extra entry is set to pending
-        * it should not be kicked during this run, since it
-        * is part of another TX operation.
+        * USB devices cannot blindly pass the skb->len as the
+        * length of the data to usb_fill_bulk_urb. Pass the skb
+        * to the driver to determine what the length should be.
         */
-       spin_lock_irqsave(&queue->lock, irqflags);
-       index = queue->index[Q_INDEX];
-       index_done = queue->index[Q_INDEX_DONE];
-       spin_unlock_irqrestore(&queue->lock, irqflags);
+       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
-       /*
-        * Start from the TX done pointer, this guarentees that we will
-        * send out all frames in the correct order.
-        */
-       if (index_done < index) {
-               for (i = index_done; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       } else {
-               for (i = index_done; i < queue->limit; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
+       usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+                         usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+                         entry->skb->data, length,
+                         rt2x00usb_interrupt_txdone, entry);
 
-               for (i = 0; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       }
+       usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+}
+
+void rt2x00usb_kick_tx_queue(struct data_queue *queue)
+{
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kick_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
 
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid)
+static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
 {
-       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
-       struct queue_entry_priv_usb *entry_priv;
-       struct queue_entry_priv_usb_bcn *bcn_priv;
-       unsigned int i;
-       bool kill_guard;
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+
+       if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+               return;
+
+       usb_kill_urb(entry_priv->urb);
 
        /*
-        * When killing the beacon queue, we must also kill
-        * the beacon guard byte.
+        * Kill guardian urb (if required by driver).
         */
-       kill_guard =
-           (qid == QID_BEACON) &&
-           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags));
+       if ((entry->queue->qid == QID_BEACON) &&
+           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+               usb_kill_urb(bcn_priv->guardian_urb);
 
        /*
-        * Cancel all entries.
+        * We need a short delay here to wait for
+        * the URB to be canceled
         */
-       for (i = 0; i < queue->limit; i++) {
-               entry_priv = queue->entries[i].priv_data;
-               usb_kill_urb(entry_priv->urb);
+       do {
+               udelay(100);
+       } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
+}
 
-               /*
-                * Kill guardian urb (if required by driver).
-                */
-               if (kill_guard) {
-                       bcn_priv = queue->entries[i].priv_data;
-                       usb_kill_urb(bcn_priv->guardian_urb);
-               }
-       }
+void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+{
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kill_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
 
-static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
 {
-       struct queue_entry *entry;
-       struct queue_entry_priv_usb *entry_priv;
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        unsigned short threshold = queue->threshold;
 
-       WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+       WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+               " invoke forced forced reset", queue->qid);
 
        /*
         * Temporarily disable the TX queue, this will force mac80211
@@ -337,28 +313,33 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
         * queue from being enabled during the txdone handler.
         */
        queue->threshold = queue->limit;
-       ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+       ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
 
        /*
-        * Reset all currently uploaded TX frames.
+        * Kill all entries in the queue, afterwards we need to
+        * wait a bit for all URBs to be cancelled.
         */
-       while (!rt2x00queue_empty(queue)) {
-               entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-               entry_priv = entry->priv_data;
-               usb_kill_urb(entry_priv->urb);
+       rt2x00usb_kill_tx_queue(queue);
 
-               /*
-                * We need a short delay here to wait for
-                * the URB to be canceled
-                */
-               do {
-                       udelay(100);
-               } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
+       /*
+        * In case that a driver has overriden the txdone_work
+        * function, we invoke the TX done through there.
+        */
+       rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
 
-               /*
-                * Invoke the TX done handler
-                */
-               rt2x00usb_work_txdone_entry(entry);
+       /*
+        * Security measure: if the driver did override the
+        * txdone_work function, and the hardware did arrive
+        * in a state which causes it to malfunction, it is
+        * possible that the driver couldn't handle the txdone
+        * event correctly. So after giving the driver the
+        * chance to cleanup, we now force a cleanup of any
+        * leftovers.
+        */
+       if (!rt2x00queue_empty(queue)) {
+               WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+                       " status handling failed, invoke hard reset", queue->qid);
+               rt2x00usb_work_txdone(&rt2x00dev->txdone_work);
        }
 
        /*
@@ -366,7 +347,15 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
         * queue again.
         */
        queue->threshold = threshold;
-       ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+       ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
+}
+
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+       WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+               " invoke forced tx handler", queue->qid);
+
+       ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
 }
 
 void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -374,8 +363,10 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
 
        tx_queue_for_each(rt2x00dev, queue) {
+               if (rt2x00queue_dma_timeout(queue))
+                       rt2x00usb_watchdog_tx_dma(queue);
                if (rt2x00queue_timeout(queue))
-                       rt2x00usb_watchdog_reset_tx(queue);
+                       rt2x00usb_watchdog_tx_status(queue);
        }
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
@@ -416,10 +407,14 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 
-       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+       if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
+       /*
+        * Report the frame as DMA done
+        */
+       rt2x00lib_dmadone(entry);
+
        /*
         * Check if the received data is simply too small
         * to be actually valid, or if the urb is signaling
@@ -432,7 +427,9 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * Schedule the delayed work for reading the RX status
         * from the device.
         */
-       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
 }
 
 /*
@@ -447,7 +444,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
         * The USB version of kill_tx_queue also works
         * on the RX queue.
         */
-       rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX);
+       rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
 
index d3d3ddc408759d755a8e55df993ee0c4853084c8..c2d997f67b3e718a9bc2fe063e5245acff3a852e 100644 (file)
@@ -379,25 +379,21 @@ struct queue_entry_priv_usb_bcn {
 
 /**
  * rt2x00usb_kick_tx_queue - Kick data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kick
+ * @queue: Data queue to kick
  *
  * This will walk through all entries of the queue and push all pending
  * frames to the hardware as a single burst.
  */
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid);
+void rt2x00usb_kick_tx_queue(struct data_queue *queue);
 
 /**
  * rt2x00usb_kill_tx_queue - Kill data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kill
+ * @queue: Data queue to kill
  *
  * This will walk through all entries of the queue and kill all
  * previously kicked frames before they can be send.
  */
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                             const enum data_queue_qid qid);
+void rt2x00usb_kill_tx_queue(struct data_queue *queue);
 
 /**
  * rt2x00usb_watchdog - Watchdog for USB communication
index 3f8d10b76fee7490516cf38be08f1a9a07d324ca..3a7759929190b78674aed60783fb5b6793124f4c 100644 (file)
@@ -1766,12 +1766,11 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                 struct sk_buff *skb,
+static void rt61pci_write_tx_desc(struct queue_entry *entry,
                                  struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1779,7 +1778,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1802,15 +1801,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2x00_desc_read(txd, 5, &word);
-       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
+       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
        rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
                           skbdesc->entry->entry_idx);
        rt2x00_set_field32(&word, TXD_W5_TX_POWER,
-                          TXPOWER_TO_DEV(rt2x00dev->tx_power));
+                          TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       if (txdesc->queue != QID_BEACON) {
+       if (txdesc->qid != QID_BEACON) {
                rt2x00_desc_read(txd, 6, &word);
                rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
                                   skbdesc->skb_dma);
@@ -1857,7 +1856,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         */
        skbdesc->desc = txd;
        skbdesc->desc_len =
-               (txdesc->queue == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
+               (txdesc->qid == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
 }
 
 /*
@@ -1882,7 +1881,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt61pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1918,34 +1917,34 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
        entry->skb = NULL;
 }
 
-static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid queue)
+static void rt61pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO));
        rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
-static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid qid)
+static void rt61pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
                return;
        }
 
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
        rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
@@ -2657,13 +2656,17 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
                tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               }
        }
 
        return 0;
index 8ca19f70aea7f0550bf064884f50aa79670409e8..87fb2201537b68d96fd2882dfc230129e98ed074 100644 (file)
@@ -1426,12 +1426,11 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                 struct sk_buff *skb,
+static void rt73usb_write_tx_desc(struct queue_entry *entry,
                                  struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txd = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -1464,7 +1463,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 0, word);
 
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1487,7 +1486,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_desc_read(txd, 5, &word);
        rt2x00_set_field32(&word, TXD_W5_TX_POWER,
-                          TXPOWER_TO_DEV(rt2x00dev->tx_power));
+                          TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
@@ -1526,7 +1525,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt73usb_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1574,6 +1573,14 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
+static void rt73usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -2091,13 +2098,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
                tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               }
        }
 
        return 0;
@@ -2259,7 +2270,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .write_beacon           = rt73usb_write_beacon,
        .get_tx_data_len        = rt73usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt73usb_kill_tx_queue,
        .fill_rxdone            = rt73usb_fill_rxdone,
        .config_shared_key      = rt73usb_config_shared_key,
        .config_pairwise_key    = rt73usb_config_pairwise_key,
index 6b942a28e6a5dd02e87cebd8f20273e234cdea10..e113d4c1fb357924d20a342d4ec214b6fde33c85 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008-2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -274,6 +272,8 @@ struct wl1251 {
        int irq;
        bool use_eeprom;
 
+       spinlock_t wl_lock;
+
        enum wl1251_state state;
        struct mutex mutex;
 
@@ -401,7 +401,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
 
 #define WL1251_DEFAULT_POWER_LEVEL 20
 
-#define WL1251_TX_QUEUE_MAX_LENGTH 20
+#define WL1251_TX_QUEUE_LOW_WATERMARK  10
+#define WL1251_TX_QUEUE_HIGH_WATERMARK 25
 
 #define WL1251_DEFAULT_BEACON_INT 100
 #define WL1251_DEFAULT_DTIM_PERIOD 1
index a8845b8f245124d3373107afd929400e9dc946c0..c7cc5c1e8a7571a5f3098a87ad71c83238a1a7e0 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 5e65f47fda8adc682be75779bccbff625ea2d117..468b47b0328a01c65b63318e78b49bfc0fd0b8b8 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 90063697e8f279f9590af39aff1e735ce408ffc7..7661bc5e46627182fe040af0e73b6265e17d9aee 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 60d7e522486c87b905646251ccb237a631b52dd9..e5c74c631374cd0c051574dff620b0a200f3d83a 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 5e4465ac08fadbbb435db0ad890edc4d610e2ae6..6ffe4cd5856140caf384ecbd4d638c86e54a2538 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 6dc3d080853c47950cb9dad1fe069f3a226f247b..b3417c02a218e597e3136fb65c8f02667b02d30a 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index e093a1c5a205598ea26c120aa8f6f3417b353e4d..54223556b3088d1b9078d6b8131ba6b2f08e185a 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -36,9 +34,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
                     mbox->scheduled_scan_channels);
 
        if (wl->scanning) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, false);
-               mutex_lock(&wl->mutex);
                wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
                wl->scanning = false;
        }
index ec456474a84260cd5bfba4f85ee4b150bec17188..30eb5d150bf75d8ca8a653a4adc27f59f186d0a7 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index b538bdd7b320f41e8abdf2516d755179d780f94e..c5daec05d9eedf058804484a0544c32f5f1fea05 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 269cefb3e7d43f20d96e3ca1902b1388fd5049e3..543f17582eadfda1375239011b5eb2efc03c050f 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index f1c232e0887fb65b2e1c51af82e3e9c9a89eac78..ad6ca68b303ffce05ee9855176e060ac8c5e4345 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index c81e95b45c14a6a8033475c874e6589b858f4dc4..faf221ca3f41b6aa4646c633d18c9620bfb55e1e 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008-2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -377,6 +375,7 @@ out:
 static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1251 *wl = hw->priv;
+       unsigned long flags;
 
        skb_queue_tail(&wl->tx_queue, skb);
 
@@ -391,16 +390,13 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * The workqueue is slow to process the tx_queue and we need stop
         * the queue here, otherwise the queue will get too long.
         */
-       if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+       if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) {
                wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
-               ieee80211_stop_queues(wl->hw);
 
-               /*
-                * FIXME: this is racy, the variable is not properly
-                * protected. Maybe fix this by removing the stupid
-                * variable altogether and checking the real queue state?
-                */
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_stop_queues(wl->hw);
                wl->tx_queue_stopped = true;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
 
        return NETDEV_TX_OK;
@@ -469,9 +465,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
        WARN_ON(wl->state != WL1251_STATE_ON);
 
        if (wl->scanning) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, true);
-               mutex_lock(&wl->mutex);
                wl->scanning = false;
        }
 
@@ -1437,5 +1431,5 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
 
 MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_FIRMWARE(WL1251_FW_NAME);
index b55cb2bd459aa0d278556f3b81d5ca7701fe209d..0b997bdfec09498f9ca5c562eac2becc202cdec0 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index c688ac57aee480cc2378c93c50f14f0f32272113..e5db81fc1dfcc8d710c6761593f6f2dcd0a3d300 100644 (file)
@@ -1,14 +1,9 @@
-#ifndef __WL1251_PS_H__
-#define __WL1251_PS_H__
-
 /*
  * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -25,6 +20,9 @@
  *
  */
 
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
+
 #include "wl1251.h"
 #include "wl1251_acx.h"
 
index d16edd9bf06c1bf9e61cb397068ba381f1da22ca..a5809019c5c19a5ced3d1f4d0b674b1e3bee6779 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 1b6294b3b996fd9f660d17c02bc1543b9bd428dd..25764592a596c26e412d300bc36d6028cfb34ce8 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index da4e53406a0ead9810568785a1f8d5fd3a3c3b1f..4448f635a4d8e8462643ac820226b95b34ee623e 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index b901b6135654f0ce00974411ad4f69628963f596..c0b68b0a9aa894e0f7e4364151313aa175973919 100644 (file)
@@ -339,4 +339,4 @@ module_init(wl1251_sdio_init);
 module_exit(wl1251_sdio_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
index 27fdfaaeb0742c780d82ccaaf2138ed485675cec..334ded9881c02ebdb680e4a5d0b2d6d5f2a29ffa 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -344,5 +342,5 @@ module_init(wl1251_spi_init);
 module_exit(wl1251_spi_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_ALIAS("spi:wl1251");
index 2e273a97e7f3ac25853485e2037aa486e88896fb..7dcf3cf7ae406f148dd94231cccaa51bc91a18ae 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 6634b3e27cfcf1c74a47fc698d348f6539cc03a4..388492a7f41f0202028c49e8badbe009bcb46da8 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
@@ -322,11 +320,6 @@ void wl1251_tx_work(struct work_struct *work)
 
                ret = wl1251_tx_frame(wl, skb);
                if (ret == -EBUSY) {
-                       /* firmware buffer is full, stop queues */
-                       wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
-                                    "stop queues");
-                       ieee80211_stop_queues(wl->hw);
-                       wl->tx_queue_stopped = true;
                        skb_queue_head(&wl->tx_queue, skb);
                        goto out;
                } else if (ret < 0) {
@@ -449,6 +442,7 @@ void wl1251_tx_complete(struct wl1251 *wl)
 {
        int i, result_index, num_complete = 0;
        struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
+       unsigned long flags;
 
        if (unlikely(wl->state != WL1251_STATE_ON))
                return;
@@ -477,6 +471,20 @@ void wl1251_tx_complete(struct wl1251 *wl)
                }
        }
 
+       if (wl->tx_queue_stopped
+           &&
+           skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){
+
+               /* firmware buffer has space, restart queues */
+               wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_wake_queues(wl->hw);
+               wl->tx_queue_stopped = false;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+
+       }
+
        /* Every completed frame needs to be acknowledged */
        if (num_complete) {
                /*
index f40eeb37f5aaf590a84a989a3bfdd93636fe5205..96011e78cd5a6751059dffb9ee3661e68d82c557 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
index 30194c0f36a9bfc57c87830b831cf63ac0077084..8e55cf8d509d8e4faa0802e3dc2d018aab97bbdf 100644 (file)
@@ -948,9 +948,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
                ieee80211_enable_dyn_ps(wl->vif);
 
        if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, true);
-               mutex_lock(&wl->mutex);
                wl->scan.state = WL1271_SCAN_STATE_IDLE;
                kfree(wl->scan.scanned_ch);
                wl->scan.scanned_ch = NULL;
index 30dc1000f563e170403968874076ec20293bef48..e4950c8e396e38a57c553c81875ab51b2aa04d43 100644 (file)
@@ -215,9 +215,7 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_DONE:
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, false);
-               mutex_lock(&wl->mutex);
 
                kfree(wl->scan.scanned_ch);
                wl->scan.scanned_ch = NULL;
index ec1690da7845b52b9c30cdc8d0d2144764141bf7..31603e8b558132818f37936ae0a99113bf43a54f 100644 (file)
  *     auth and assoc steps. For this, you need to specify the SSID in a
  *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
  *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *     It is also sent as an event, with the BSSID and response IEs when the
  *     connection is established or failed to be established. This can be
  *     determined by the STATUS_CODE attribute.
@@ -686,6 +688,15 @@ enum nl80211_commands {
  *     request, the driver will assume that the port is unauthorized until
  *     authorized by user space. Otherwise, port is marked authorized by
  *     default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *     ethertype that will be used for key negotiation. It can be
+ *     specified with the associate and connect commands. If it is not
+ *     specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *     attribute is also used as a flag in the wiphy information to
+ *     indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *     ethertype frames used for key negotiation must not be encrypted.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *     We recommend using nested, driver-specific attributes within this.
@@ -951,6 +962,9 @@ enum nl80211_attrs {
        NL80211_ATTR_RX_FRAME_TYPES,
        NL80211_ATTR_FRAME_TYPE,
 
+       NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+       NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index a223ecbc71eff8160c0c0b96921cd4e81e0e9d4f..a20bccf0b5c2679c7e28b0ac859380823b324931 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index f2740537b5d6704f68e115cdc4e95af3a54d6639..4c8c727d0cca04abe49fd01594378d38ddf12f3e 100644 (file)
@@ -763,6 +763,10 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
  *     sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
  *     required to assume that the port is unauthorized until authorized by
  *     user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ *     allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ *     protocol frames.
  */
 struct cfg80211_crypto_settings {
        u32 wpa_versions;
@@ -772,6 +776,8 @@ struct cfg80211_crypto_settings {
        int n_akm_suites;
        u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
        bool control_port;
+       __be16 control_port_ethertype;
+       bool control_port_no_encrypt;
 };
 
 /**
@@ -1293,15 +1299,19 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
  *     on a VLAN interface)
  * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
+ *     control port protocol ethertype. The device also honours the
+ *     control_port_no_encrypt flag.
  */
 enum wiphy_flags {
-       WIPHY_FLAG_CUSTOM_REGULATORY    = BIT(0),
-       WIPHY_FLAG_STRICT_REGULATORY    = BIT(1),
-       WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
-       WIPHY_FLAG_NETNS_OK             = BIT(3),
-       WIPHY_FLAG_PS_ON_BY_DEFAULT     = BIT(4),
-       WIPHY_FLAG_4ADDR_AP             = BIT(5),
-       WIPHY_FLAG_4ADDR_STATION        = BIT(6),
+       WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
+       WIPHY_FLAG_STRICT_REGULATORY            = BIT(1),
+       WIPHY_FLAG_DISABLE_BEACON_HINTS         = BIT(2),
+       WIPHY_FLAG_NETNS_OK                     = BIT(3),
+       WIPHY_FLAG_PS_ON_BY_DEFAULT             = BIT(4),
+       WIPHY_FLAG_4ADDR_AP                     = BIT(5),
+       WIPHY_FLAG_4ADDR_STATION                = BIT(6),
+       WIPHY_FLAG_CONTROL_PORT_PROTOCOL        = BIT(7),
 };
 
 struct mac_address {
index 2a18113660763db65db6d8e7b124999f0282bccf..f91fc331369bb22f0ec6463e0511e180cf1fa902 100644 (file)
@@ -1242,8 +1242,8 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
  * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
  * with hardware wakeup and sleep states. Driver is responsible for waking
- * up the hardware before issueing commands to the hardware and putting it
- * back to sleep at approriate times.
+ * up the hardware before issuing commands to the hardware and putting it
+ * back to sleep at appropriate times.
  *
  * When PS is enabled, hardware needs to wakeup for beacons and receive the
  * buffered multicast/broadcast frames after the beacon. Also it must be
@@ -1264,7 +1264,7 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * there's data traffic and still saving significantly power in idle
  * periods.
  *
- * Dynamic powersave is supported by simply mac80211 enabling and disabling
+ * Dynamic powersave is simply supported by mac80211 enabling and disabling
  * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS
  * flag and mac80211 will handle everything automatically. Additionally,
  * hardware having support for the dynamic PS feature may set the
@@ -1537,6 +1537,12 @@ enum ieee80211_ampdu_mlme_action {
  *     negative error code (which will be seen in userspace.)
  *     Must be implemented and can sleep.
  *
+ * @change_interface: Called when a netdevice changes type. This callback
+ *     is optional, but only if it is supported can interface types be
+ *     switched while the interface is UP. The callback may sleep.
+ *     Note that while an interface is being switched, it will not be
+ *     found by the interface iteration callbacks.
+ *
  * @remove_interface: Notifies a driver that an interface is going down.
  *     The @stop callback is called after this if it is the last interface
  *     and no monitor interfaces are present.
@@ -1693,6 +1699,9 @@ struct ieee80211_ops {
        void (*stop)(struct ieee80211_hw *hw);
        int (*add_interface)(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
+       int (*change_interface)(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               enum nl80211_iftype new_type);
        void (*remove_interface)(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif);
        int (*config)(struct ieee80211_hw *hw, u32 changed);
@@ -2268,7 +2277,8 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
  *
  * When hardware scan offload is used (i.e. the hw_scan() callback is
  * assigned) this function needs to be called by the driver to notify
- * mac80211 that the scan finished.
+ * mac80211 that the scan finished. This function can be called from
+ * any context, including hardirq context.
  *
  * @hw: the hardware that finished the scan
  * @aborted: set to true if scan was aborted
@@ -2458,7 +2468,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER and
  * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
  * hardware is not receiving beacons with this function.
  */
@@ -2469,7 +2479,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER, and
  * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
  * needs to inform if the connection to the AP has been lost.
  *
index 94787d21282c37329215dcb822af8b27fa53c554..5de1ca3f17b93bd13db9c4ba762fd2df8d7aa276 100644 (file)
 #include "rate.h"
 #include "mesh.h"
 
-static bool nl80211_type_check(enum nl80211_iftype type)
-{
-       switch (type) {
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_MONITOR:
-#ifdef CONFIG_MAC80211_MESH
-       case NL80211_IFTYPE_MESH_POINT:
-#endif
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_WDS:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool nl80211_params_check(enum nl80211_iftype type,
-                                struct vif_params *params)
-{
-       if (!nl80211_type_check(type))
-               return false;
-
-       return true;
-}
-
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
                               enum nl80211_iftype type, u32 *flags,
                               struct vif_params *params)
@@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
        struct ieee80211_sub_if_data *sdata;
        int err;
 
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        err = ieee80211_if_add(local, name, &dev, type, params);
        if (err || type != NL80211_IFTYPE_MONITOR || !flags)
                return err;
@@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret;
 
-       if (ieee80211_sdata_running(sdata))
-               return -EBUSY;
-
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
@@ -114,16 +78,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, const u8 *mac_addr,
                             struct key_params *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta = NULL;
        struct ieee80211_key *key;
        int err;
 
-       if (!netif_running(dev))
+       if (!ieee80211_sdata_running(sdata))
                return -ENETDOWN;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
        /* reject WEP and TKIP keys if WEP failed to initialize */
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
@@ -152,9 +114,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                }
        }
 
-       ieee80211_key_link(key, sdata, sta);
+       err = ieee80211_key_link(key, sdata, sta);
+       if (err)
+               ieee80211_key_free(sdata->local, key);
 
-       err = 0;
  out_unlock:
        mutex_unlock(&sdata->local->sta_mtx);
 
@@ -1123,9 +1086,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.uapsd = false;
 
        if (drv_conf_tx(local, params->queue, &p)) {
-               printk(KERN_DEBUG "%s: failed to set TX queue "
-                      "parameters for queue %d\n",
-                      wiphy_name(local->hw.wiphy), params->queue);
+               wiphy_debug(local->hw.wiphy,
+                           "failed to set TX queue parameters for queue %d\n",
+                           params->queue);
                return -EINVAL;
        }
 
index a694c593ff6ac1e17479ae07d26ad1fd02f258ba..e81ef4e8cb323eeca8ea32492a23cdb96f7a4b43 100644 (file)
@@ -85,13 +85,15 @@ static ssize_t tsf_write(struct file *file,
        if (strncmp(buf, "reset", 5) == 0) {
                if (local->ops->reset_tsf) {
                        drv_reset_tsf(local);
-                       printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy));
+                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
                }
        } else {
                tsf = simple_strtoul(buf, NULL, 0);
                if (local->ops->set_tsf) {
                        drv_set_tsf(local, tsf);
-                       printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf);
+                       wiphy_info(local->hw.wiphy,
+                                  "debugfs set TSF to %#018llx\n", tsf);
+
                }
        }
 
index 14123dce544bf960a57d6f06fdbda6bbcc83f88a..6064b7b09e0142f719b1e744ee124267f8d61d1a 100644 (file)
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
        return ret;
 }
 
+static inline int drv_change_interface(struct ieee80211_local *local,
+                                      struct ieee80211_sub_if_data *sdata,
+                                      enum nl80211_iftype type)
+{
+       int ret;
+
+       might_sleep();
+
+       trace_drv_change_interface(local, sdata, type);
+       ret = local->ops->change_interface(&local->hw, &sdata->vif, type);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
 static inline void drv_remove_interface(struct ieee80211_local *local,
                                        struct ieee80211_vif *vif)
 {
index b5a95582d816394ef01e8812b1bebc31b36f02b3..f6f3d89e43faa206a56888b200030e8f3ed151e8 100644 (file)
@@ -136,6 +136,31 @@ TRACE_EVENT(drv_add_interface,
        )
 );
 
+TRACE_EVENT(drv_change_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                enum nl80211_iftype type),
+
+       TP_ARGS(local, sdata, type),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u32, new_type)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->new_type = type;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type
+       )
+);
+
 TRACE_EVENT(drv_remove_interface,
        TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
 
index 32af97108425792cfb727143919d14bb9df43772..1a3aae54f0cf88a44d9fa819fd94d1518978d8fd 100644 (file)
@@ -427,8 +427,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                return NULL;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), addr, sdata->name);
+       wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
+                   addr, sdata->name);
 #endif
 
        sta = sta_info_alloc(sdata, addr, gfp);
index e73ae51dc036cefe626637098ded15cba7963379..4e635e2fabdb14d640b3e5832dc00f45ecb65c4a 100644 (file)
@@ -50,12 +50,6 @@ struct ieee80211_local;
  * increased memory use (about 2 kB of RAM per entry). */
 #define IEEE80211_FRAGMENT_MAX 4
 
-/*
- * Time after which we ignore scan results and no longer report/use
- * them in any way.
- */
-#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
-
 #define TU_TO_EXP_TIME(x)      (jiffies + usecs_to_jiffies((x) * 1024))
 
 #define IEEE80211_DEFAULT_UAPSD_QUEUES \
@@ -374,6 +368,13 @@ struct ieee80211_if_managed {
         */
        int ave_beacon_signal;
 
+       /*
+        * Number of Beacon frames used in ave_beacon_signal. This can be used
+        * to avoid generating less reliable cqm events that would be based
+        * only on couple of received frames.
+        */
+       unsigned int count_beacon_signal;
+
        /*
         * Last Beacon frame signal strength average (ave_beacon_signal / 16)
         * that triggered a cqm event. 0 indicates that no event has been
@@ -478,6 +479,19 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
 };
 
+/**
+ * enum ieee80211_sdata_state_bits - virtual interface state bits
+ * @SDATA_STATE_RUNNING: virtual interface is up & running; this
+ *     mirrors netif_running() but is separate for interface type
+ *     change handling while the interface is up
+ * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
+ *     mode, so queues are stopped
+ */
+enum ieee80211_sdata_state_bits {
+       SDATA_STATE_RUNNING,
+       SDATA_STATE_OFFCHANNEL,
+};
+
 struct ieee80211_sub_if_data {
        struct list_head list;
 
@@ -491,6 +505,8 @@ struct ieee80211_sub_if_data {
 
        unsigned int flags;
 
+       unsigned long state;
+
        int drop_unencrypted;
 
        char name[IFNAMSIZ];
@@ -515,6 +531,8 @@ struct ieee80211_sub_if_data {
        struct ieee80211_key *default_mgmt_key;
 
        u16 sequence_number;
+       __be16 control_port_protocol;
+       bool control_port_no_encrypt;
 
        struct work_struct work;
        struct sk_buff_head skb_queue;
@@ -602,11 +620,17 @@ enum queue_stop_reason {
  *     determine if we are on the operating channel or not
  * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
  *     gets only set in conjunction with SCAN_SW_SCANNING
+ * @SCAN_COMPLETED: Set for our scan work function when the driver reported
+ *     that the scan completed.
+ * @SCAN_ABORTED: Set for our scan work function when the driver reported
+ *     a scan complete for an aborted scan.
  */
 enum {
        SCAN_SW_SCANNING,
        SCAN_HW_SCANNING,
        SCAN_OFF_CHANNEL,
+       SCAN_COMPLETED,
+       SCAN_ABORTED,
 };
 
 /**
@@ -662,6 +686,8 @@ struct ieee80211_local {
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
        unsigned int filter_flags; /* FIF_* */
 
+       bool wiphy_ciphers_allocated;
+
        /* protects the aggregated multicast list and filter calls */
        spinlock_t filter_lock;
 
@@ -1083,7 +1109,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
-       return netif_running(sdata->dev);
+       return test_bit(SDATA_STATE_RUNNING, &sdata->state);
 }
 
 /* tx handling */
@@ -1160,6 +1186,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw);
 
 static inline int __ieee80211_resume(struct ieee80211_hw *hw)
 {
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+               "%s: resume with hardware scan still in progress\n",
+               wiphy_name(hw->wiphy));
+
        return ieee80211_reconfig(hw_to_local(hw));
 }
 #else
index 86f434f234aea765e65355edad3caae4bf8a04a0..c1cc200ac81f29a7d50d494e6de45277b99f6683 100644 (file)
@@ -94,21 +94,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
                         type2 == NL80211_IFTYPE_AP_VLAN));
 }
 
-static int ieee80211_open(struct net_device *dev)
+static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
+                                           enum nl80211_iftype iftype)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_sub_if_data *nsdata;
        struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       u32 changed = 0;
-       int res;
-       u32 hw_reconf_flags = 0;
-       u8 null_addr[ETH_ALEN] = {0};
+       struct ieee80211_sub_if_data *nsdata;
+       struct net_device *dev = sdata->dev;
 
-       /* fail early if user set an invalid address */
-       if (compare_ether_addr(dev->dev_addr, null_addr) &&
-           !is_valid_ether_addr(dev->dev_addr))
-               return -EADDRNOTAVAIL;
+       ASSERT_RTNL();
 
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
@@ -125,7 +118,7 @@ static int ieee80211_open(struct net_device *dev)
                         * belonging to the same hardware. Then, however, we're
                         * faced with having to adopt two different TSF timers...
                         */
-                       if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+                       if (iftype == NL80211_IFTYPE_ADHOC &&
                            nsdata->vif.type == NL80211_IFTYPE_ADHOC)
                                return -EBUSY;
 
@@ -139,19 +132,36 @@ static int ieee80211_open(struct net_device *dev)
                        /*
                         * check whether it may have the same address
                         */
-                       if (!identical_mac_addr_allowed(sdata->vif.type,
+                       if (!identical_mac_addr_allowed(iftype,
                                                        nsdata->vif.type))
                                return -ENOTUNIQ;
 
                        /*
                         * can only add VLANs to enabled APs
                         */
-                       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+                       if (iftype == NL80211_IFTYPE_AP_VLAN &&
                            nsdata->vif.type == NL80211_IFTYPE_AP)
                                sdata->bss = &nsdata->u.ap;
                }
        }
 
+       return 0;
+}
+
+/*
+ * 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
+ * checks should be in ieee80211_check_concurrent_iface.
+ */
+static int ieee80211_do_open(struct net_device *dev, bool coming_up)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+       u32 changed = 0;
+       int res;
+       u32 hw_reconf_flags = 0;
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_WDS:
                if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
@@ -195,33 +205,22 @@ static int ieee80211_open(struct net_device *dev)
        }
 
        /*
-        * Check all interfaces and copy the hopefully now-present
-        * MAC address to those that have the special null one.
+        * Copy the hopefully now-present MAC address to
+        * this interface, if it has the special null one.
         */
-       list_for_each_entry(nsdata, &local->interfaces, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               /*
-                * No need to check running since we do not allow
-                * it to start up with this invalid address.
-                */
-               if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
-                       memcpy(ndev->dev_addr,
-                              local->hw.wiphy->perm_addr,
-                              ETH_ALEN);
-                       memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+       if (is_zero_ether_addr(dev->dev_addr)) {
+               memcpy(dev->dev_addr,
+                      local->hw.wiphy->perm_addr,
+                      ETH_ALEN);
+               memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
+               if (!is_valid_ether_addr(dev->dev_addr)) {
+                       if (!local->open_count)
+                               drv_stop(local);
+                       return -EADDRNOTAVAIL;
                }
        }
 
-       /*
-        * Validate the MAC address for this device.
-        */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               if (!local->open_count)
-                       drv_stop(local);
-               return -EADDRNOTAVAIL;
-       }
-
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                /* no need to tell driver */
@@ -255,9 +254,11 @@ static int ieee80211_open(struct net_device *dev)
                netif_carrier_on(dev);
                break;
        default:
-               res = drv_add_interface(local, &sdata->vif);
-               if (res)
-                       goto err_stop;
+               if (coming_up) {
+                       res = drv_add_interface(local, &sdata->vif);
+                       if (res)
+                               goto err_stop;
+               }
 
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        local->fif_other_bss++;
@@ -313,7 +314,9 @@ static int ieee80211_open(struct net_device *dev)
        hw_reconf_flags |= __ieee80211_recalc_idle(local);
        mutex_unlock(&local->mtx);
 
-       local->open_count++;
+       if (coming_up)
+               local->open_count++;
+
        if (hw_reconf_flags) {
                ieee80211_hw_config(local, hw_reconf_flags);
                /*
@@ -328,6 +331,8 @@ static int ieee80211_open(struct net_device *dev)
 
        netif_tx_start_all_queues(dev);
 
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        return 0;
  err_del_interface:
        drv_remove_interface(local, &sdata->vif);
@@ -341,19 +346,38 @@ static int ieee80211_open(struct net_device *dev)
        return res;
 }
 
-static int ieee80211_stop(struct net_device *dev)
+static int ieee80211_open(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int err;
+
+       /* fail early if user set an invalid address */
+       if (!is_zero_ether_addr(dev->dev_addr) &&
+           !is_valid_ether_addr(dev->dev_addr))
+               return -EADDRNOTAVAIL;
+
+       err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
+       if (err)
+               return err;
+
+       return ieee80211_do_open(dev, true);
+}
+
+static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
+                             bool going_down)
+{
        struct ieee80211_local *local = sdata->local;
        unsigned long flags;
        struct sk_buff *skb, *tmp;
        u32 hw_reconf_flags = 0;
        int i;
 
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        /*
         * Stop TX on this interface first.
         */
-       netif_tx_stop_all_queues(dev);
+       netif_tx_stop_all_queues(sdata->dev);
 
        /*
         * Purge work for this interface.
@@ -370,12 +394,9 @@ static int ieee80211_stop(struct net_device *dev)
         * (because if we remove a STA after ops->remove_interface()
         * the driver will have removed the vif info already!)
         *
-        * We could relax this and only unlink the stations from the
-        * hash table and list but keep them on a per-sdata list that
-        * will be inserted back again when the interface is brought
-        * up again, but I don't currently see a use case for that,
-        * except with WDS which gets a STA entry created when it is
-        * brought up.
+        * This is relevant only in AP, WDS and mesh modes, since in
+        * all other modes we've already removed all stations when
+        * disconnecting etc.
         */
        sta_info_flush(local, sdata);
 
@@ -394,11 +415,12 @@ static int ieee80211_stop(struct net_device *dev)
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                local->fif_pspoll--;
 
-       netif_addr_lock_bh(dev);
+       netif_addr_lock_bh(sdata->dev);
        spin_lock_bh(&local->filter_lock);
-       __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len);
+       __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
+                        sdata->dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
-       netif_addr_unlock_bh(dev);
+       netif_addr_unlock_bh(sdata->dev);
 
        ieee80211_configure_filter(local);
 
@@ -410,11 +432,21 @@ static int ieee80211_stop(struct net_device *dev)
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
                struct beacon_data *old_beacon = sdata->u.ap.beacon;
 
+               /* sdata_running will return false, so this will disable */
+               ieee80211_bss_info_change_notify(sdata,
+                                                BSS_CHANGED_BEACON_ENABLED);
+
                /* remove beacon */
                rcu_assign_pointer(sdata->u.ap.beacon, NULL);
                synchronize_rcu();
                kfree(old_beacon);
 
+               /* free all potentially still buffered bcast frames */
+               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+                       local->total_ps_buffered--;
+                       dev_kfree_skb(skb);
+               }
+
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
                                         u.vlan.list)
@@ -422,7 +454,8 @@ static int ieee80211_stop(struct net_device *dev)
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
        }
 
-       local->open_count--;
+       if (going_down)
+               local->open_count--;
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
@@ -454,27 +487,6 @@ static int ieee80211_stop(struct net_device *dev)
 
                ieee80211_configure_filter(local);
                break;
-       case NL80211_IFTYPE_STATION:
-               del_timer_sync(&sdata->u.mgd.chswitch_timer);
-               del_timer_sync(&sdata->u.mgd.timer);
-               del_timer_sync(&sdata->u.mgd.conn_mon_timer);
-               del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
-               /*
-                * If any of the timers fired while we waited for it, it will
-                * have queued its work. Now the work will be running again
-                * but will not rearm the timer again because it checks
-                * whether the interface is running, which, at this point,
-                * it no longer is.
-                */
-               cancel_work_sync(&sdata->u.mgd.chswitch_work);
-               cancel_work_sync(&sdata->u.mgd.monitor_work);
-               cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
-
-               /* fall through */
-       case NL80211_IFTYPE_ADHOC:
-               if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-                       del_timer_sync(&sdata->u.ibss.timer);
-               /* fall through */
        case NL80211_IFTYPE_MESH_POINT:
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        /* other_bss and allmulti are always set on mesh
@@ -502,18 +514,21 @@ static int ieee80211_stop(struct net_device *dev)
                        ieee80211_scan_cancel(local);
 
                /*
-                * Disable beaconing for AP and mesh, IBSS can't
-                * still be joined to a network at this point.
+                * Disable beaconing here for mesh only, AP and IBSS
+                * are already taken care of.
                 */
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+               if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                        ieee80211_bss_info_change_notify(sdata,
                                BSS_CHANGED_BEACON_ENABLED);
-               }
 
-               /* free all remaining keys, there shouldn't be any */
+               /*
+                * Free all remaining keys, there shouldn't be any,
+                * except maybe group keys in AP more or WDS?
+                */
                ieee80211_free_keys(sdata);
-               drv_remove_interface(local, &sdata->vif);
+
+               if (going_down)
+                       drv_remove_interface(local, &sdata->vif);
        }
 
        sdata->bss = NULL;
@@ -549,6 +564,13 @@ static int ieee80211_stop(struct net_device *dev)
                }
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+static int ieee80211_stop(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       ieee80211_do_stop(sdata, true);
 
        return 0;
 }
@@ -593,8 +615,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct beacon_data *beacon;
-       struct sk_buff *skb;
        int flushed;
        int i;
 
@@ -607,37 +627,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
                __skb_queue_purge(&sdata->fragments[i].skb_list);
        sdata->fragment_next = 0;
 
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-               beacon = sdata->u.ap.beacon;
-               rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-               synchronize_rcu();
-               kfree(beacon);
-
-               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-                       local->total_ps_buffered--;
-                       dev_kfree_skb(skb);
-               }
-
-               break;
-       case NL80211_IFTYPE_MESH_POINT:
-               if (ieee80211_vif_is_mesh(&sdata->vif))
-                       mesh_rmc_free(sdata);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               if (WARN_ON(sdata->u.ibss.presp))
-                       kfree_skb(sdata->u.ibss.presp);
-               break;
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_WDS:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_MONITOR:
-               break;
-       case NL80211_IFTYPE_UNSPECIFIED:
-       case NUM_NL80211_IFTYPES:
-               BUG();
-               break;
-       }
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               mesh_rmc_free(sdata);
 
        flushed = sta_info_flush(local, sdata);
        WARN_ON(flushed);
@@ -855,6 +846,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        sdata->dev->netdev_ops = &ieee80211_dataif_ops;
        sdata->wdev.iftype = type;
 
+       sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
+       sdata->control_port_no_encrypt = false;
+
        /* only monitor differs */
        sdata->dev->type = ARPHRD_ETHER;
 
@@ -894,9 +888,72 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        ieee80211_debugfs_add_netdev(sdata);
 }
 
+static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
+                                          enum nl80211_iftype type)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret, err;
+
+       ASSERT_RTNL();
+
+       if (!local->ops->change_interface)
+               return -EBUSY;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               /*
+                * Could maybe also all others here?
+                * Just not sure how that interacts
+                * with the RX/config path e.g. for
+                * mesh.
+                */
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       switch (type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               /*
+                * Could probably support everything
+                * but WDS here (WDS do_open can fail
+                * under memory pressure, which this
+                * code isn't prepared to handle).
+                */
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       ret = ieee80211_check_concurrent_iface(sdata, type);
+       if (ret)
+               return ret;
+
+       ieee80211_do_stop(sdata, false);
+
+       ieee80211_teardown_sdata(sdata->dev);
+
+       ret = drv_change_interface(local, sdata, type);
+       if (ret)
+               type = sdata->vif.type;
+
+       ieee80211_setup_sdata(sdata, type);
+
+       err = ieee80211_do_open(sdata->dev, false);
+       WARN(err, "type change: do_open returned %d", err);
+
+       return ret;
+}
+
 int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
                             enum nl80211_iftype type)
 {
+       int ret;
+
        ASSERT_RTNL();
 
        if (type == sdata->vif.type)
@@ -907,18 +964,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
            type == NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
-       /*
-        * We could, here, on changes between IBSS/STA/MESH modes,
-        * invoke an MLME function instead that disassociates etc.
-        * and goes into the requested mode.
-        */
-
-       if (ieee80211_sdata_running(sdata))
-               return -EBUSY;
-
-       /* Purge and reset type-dependent state. */
-       ieee80211_teardown_sdata(sdata->dev);
-       ieee80211_setup_sdata(sdata, type);
+       if (ieee80211_sdata_running(sdata)) {
+               ret = ieee80211_runtime_change_iftype(sdata, type);
+               if (ret)
+                       return ret;
+       } else {
+               /* Purge and reset type-dependent state. */
+               ieee80211_teardown_sdata(sdata->dev);
+               ieee80211_setup_sdata(sdata, type);
+       }
 
        /* reset some values that shouldn't be kept across type changes */
        sdata->vif.bss_conf.basic_rates =
@@ -1175,8 +1229,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
                return 0;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: device no longer idle - %s\n",
-              wiphy_name(local->hw.wiphy), reason);
+       wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
 #endif
 
        local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
@@ -1189,8 +1242,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
                return 0;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: device now idle\n",
-              wiphy_name(local->hw.wiphy));
+       wiphy_debug(local->hw.wiphy, "device now idle\n");
 #endif
 
        drv_flush(local, false);
index 9c27c53cfae58a167ccf35d44f39b88e9fde5835..3570f8c2bb401d3d4d20cbac6dbc0fddfb395235 100644 (file)
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
        return NULL;
 }
 
-static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
+static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_sta *sta;
@@ -68,8 +68,10 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        might_sleep();
 
-       if (!key->local->ops->set_key)
-               return;
+       if (!key->local->ops->set_key) {
+               ret = -EOPNOTSUPP;
+               goto out_unsupported;
+       }
 
        assert_key_lock(key->local);
 
@@ -87,10 +89,27 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
        if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
-               printk(KERN_ERR "mac80211-%s: failed to set key "
-                      "(%d, %pM) to hardware (%d)\n",
-                      wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+               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;
+               }
+       }
+
+       return ret;
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
@@ -121,10 +140,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          sta, &key->conf);
 
        if (ret)
-               printk(KERN_ERR "mac80211-%s: failed to remove key "
-                      "(%d, %pM) from hardware (%d)\n",
-                      wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+               wiphy_err(key->local->hw.wiphy,
+                         "failed to remove key (%d, %pM) from hardware (%d)\n",
+                         key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
@@ -331,12 +349,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
        kfree(key);
 }
 
-void ieee80211_key_link(struct ieee80211_key *key,
-                       struct ieee80211_sub_if_data *sdata,
-                       struct sta_info *sta)
+int ieee80211_key_link(struct ieee80211_key *key,
+                      struct ieee80211_sub_if_data *sdata,
+                      struct sta_info *sta)
 {
        struct ieee80211_key *old_key;
-       int idx;
+       int idx, ret;
 
        BUG_ON(!sdata);
        BUG_ON(!key);
@@ -391,9 +409,11 @@ void ieee80211_key_link(struct ieee80211_key *key,
 
        ieee80211_debugfs_key_add(key);
 
-       ieee80211_key_enable_hw_accel(key);
+       ret = ieee80211_key_enable_hw_accel(key);
 
        mutex_unlock(&sdata->local->key_mtx);
+
+       return ret;
 }
 
 static void __ieee80211_key_free(struct ieee80211_key *key)
index 53b5ce12536f629bc4fb99365662ca0c2047bfb2..cb9a4a65cc68fae008b1ea79a0c0ff84d9651cb8 100644 (file)
@@ -130,9 +130,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
  * Insert a key into data structures (sdata, sta if necessary)
  * to make it used, free old key.
  */
-void ieee80211_key_link(struct ieee80211_key *key,
-                       struct ieee80211_sub_if_data *sdata,
-                       struct sta_info *sta);
+int __must_check ieee80211_key_link(struct ieee80211_key *key,
+                                   struct ieee80211_sub_if_data *sdata,
+                                   struct sta_info *sta);
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
index a53feac4618c487f6d0155f4e65322d62a43ba7d..a06b6ee63c07d7ac64f2440dba3fcf4b8fd40daa 100644 (file)
@@ -305,7 +305,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 
        trace_api_restart_hw(local);
 
-       /* use this reason, __ieee80211_resume will unblock it */
+       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);
 
@@ -339,9 +345,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        struct ieee80211_if_managed *ifmgd;
        int c = 0;
 
-       if (!netif_running(ndev))
-               return NOTIFY_DONE;
-
        /* Make sure it's our interface that got changed */
        if (!wdev)
                return NOTIFY_DONE;
@@ -352,6 +355,9 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
        bss_conf = &sdata->vif.bss_conf;
 
+       if (!ieee80211_sdata_running(sdata))
+               return NOTIFY_DONE;
+
        /* ARP filtering is only supported in managed mode */
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return NOTIFY_DONE;
@@ -622,6 +628,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        /* mac80211 always supports monitor */
        local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
 
+#ifndef CONFIG_MAC80211_MESH
+       /* mesh depends on Kconfig, but drivers should set it if they want */
+       local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
+#endif
+
+       /* mac80211 supports control port protocol changing */
+       local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
+
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
@@ -657,13 +671,40 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
 
-       local->hw.wiphy->cipher_suites = cipher_suites;
-       local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-       if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
-               local->hw.wiphy->n_cipher_suites--;
+       /* Set up cipher suites unless driver already did */
+       if (!local->hw.wiphy->cipher_suites) {
+               local->hw.wiphy->cipher_suites = cipher_suites;
+               local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+               if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
+                       local->hw.wiphy->n_cipher_suites--;
+       }
        if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
-               local->hw.wiphy->cipher_suites += 2;
-               local->hw.wiphy->n_cipher_suites -= 2;
+               if (local->hw.wiphy->cipher_suites == cipher_suites) {
+                       local->hw.wiphy->cipher_suites += 2;
+                       local->hw.wiphy->n_cipher_suites -= 2;
+               } else {
+                       u32 *suites;
+                       int r, w = 0;
+
+                       /* Filter out WEP */
+
+                       suites = kmemdup(
+                               local->hw.wiphy->cipher_suites,
+                               sizeof(u32) * local->hw.wiphy->n_cipher_suites,
+                               GFP_KERNEL);
+                       if (!suites)
+                               return -ENOMEM;
+                       for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
+                               u32 suite = local->hw.wiphy->cipher_suites[r];
+                               if (suite == WLAN_CIPHER_SUITE_WEP40 ||
+                                   suite == WLAN_CIPHER_SUITE_WEP104)
+                                       continue;
+                               suites[w++] = suite;
+                       }
+                       local->hw.wiphy->cipher_suites = suites;
+                       local->hw.wiphy->n_cipher_suites = w;
+                       local->wiphy_ciphers_allocated = true;
+               }
        }
 
        result = wiphy_register(local->hw.wiphy);
@@ -713,16 +754,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        result = ieee80211_wep_init(local);
        if (result < 0)
-               printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
-                      wiphy_name(local->hw.wiphy), result);
+               wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
+                           result);
 
        rtnl_lock();
 
        result = ieee80211_init_rate_ctrl_alg(local,
                                              hw->rate_control_algorithm);
        if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               wiphy_debug(local->hw.wiphy,
+                           "Failed to initialize rate control algorithm\n");
                goto fail_rate;
        }
 
@@ -731,8 +772,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                result = ieee80211_if_add(local, "wlan%d", NULL,
                                          NL80211_IFTYPE_STATION, NULL);
                if (result)
-                       printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
-                              wiphy_name(local->hw.wiphy));
+                       wiphy_warn(local->hw.wiphy,
+                                  "Failed to add default virtual iface\n");
        }
 
        rtnl_unlock();
@@ -778,6 +819,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
        kfree(local->int_scan_req);
        return result;
 }
@@ -807,6 +850,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
+       cancel_work_sync(&local->restart_work);
        cancel_work_sync(&local->reconfig_filter);
 
        ieee80211_clear_tx_pending(local);
@@ -815,8 +859,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        if (skb_queue_len(&local->skb_queue) ||
            skb_queue_len(&local->skb_queue_unreliable))
-               printk(KERN_WARNING "%s: skb_queue not empty\n",
-                      wiphy_name(local->hw.wiphy));
+               wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
        skb_queue_purge(&local->skb_queue);
        skb_queue_purge(&local->skb_queue_unreliable);
 
@@ -835,6 +878,9 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        mutex_destroy(&local->iflist_mtx);
        mutex_destroy(&local->mtx);
 
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index 38996a44aa8ef9ea221eea71cd01507f2ddf28b6..0cb822cc12e9c52618ddb18d5503db43765b9f11 100644 (file)
  */
 #define IEEE80211_SIGNAL_AVE_WEIGHT    3
 
+/*
+ * How many Beacon frames need to have been used in average signal strength
+ * before starting to indicate signal change events.
+ */
+#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
+
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
@@ -778,16 +784,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                params.uapsd = uapsd;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
-                      "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
-                      wiphy_name(local->hw.wiphy), queue, aci, acm,
-                      params.aifs, params.cw_min, params.cw_max, params.txop,
-                      params.uapsd);
+               wiphy_debug(local->hw.wiphy,
+                           "WMM queue=%d aci=%d acm=%d aifs=%d "
+                           "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+                           queue, aci, acm,
+                           params.aifs, params.cw_min, params.cw_max,
+                           params.txop, params.uapsd);
 #endif
                if (drv_conf_tx(local, queue, &params))
-                       printk(KERN_DEBUG "%s: failed to set TX queue "
-                              "parameters for queue %d\n",
-                              wiphy_name(local->hw.wiphy), queue);
+                       wiphy_debug(local->hw.wiphy,
+                                   "failed to set TX queue parameters for queue %d\n",
+                                   queue);
        }
 
        /* enable WMM or activate new settings */
@@ -990,6 +997,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        if (remove_sta)
                sta_info_destroy_addr(sdata, bssid);
+
+       del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+       del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
+       del_timer_sync(&sdata->u.mgd.timer);
+       del_timer_sync(&sdata->u.mgd.chswitch_timer);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1547,15 +1559,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ifmgd->last_beacon_signal = rx_status->signal;
        if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
                ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
-               ifmgd->ave_beacon_signal = rx_status->signal;
+               ifmgd->ave_beacon_signal = rx_status->signal * 16;
                ifmgd->last_cqm_event_signal = 0;
+               ifmgd->count_beacon_signal = 1;
        } else {
                ifmgd->ave_beacon_signal =
                        (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
                         (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
                         ifmgd->ave_beacon_signal) / 16;
+               ifmgd->count_beacon_signal++;
        }
        if (bss_conf->cqm_rssi_thold &&
+           ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
            !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
                int sig = ifmgd->ave_beacon_signal / 16;
                int last_event = ifmgd->last_cqm_event_signal;
@@ -2261,6 +2276,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        else
                ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 
+       sdata->control_port_protocol = req->crypto.control_port_ethertype;
+       sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
+
        ieee80211_add_work(wk);
        return 0;
 }
index c36b1911987afec08262139ccaaf5e7887a17735..eeacaa59380a4c4cc91fe7f48d8ca622a13396b0 100644 (file)
@@ -112,8 +112,10 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
                 * used from user space controlled off-channel operations.
                 */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-                   sdata->vif.type != NL80211_IFTYPE_MONITOR)
+                   sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
                        netif_tx_stop_all_queues(sdata->dev);
+               }
        }
        mutex_unlock(&local->iflist_mtx);
 }
@@ -131,6 +133,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
                        continue;
 
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
                        netif_tx_stop_all_queues(sdata->dev);
                        if (sdata->u.mgd.associated)
                                ieee80211_offchannel_ps_enable(sdata);
@@ -155,8 +158,20 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                                ieee80211_offchannel_ps_disable(sdata);
                }
 
-               if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+                       clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+                       /*
+                        * This may wake up queues even though the driver
+                        * currently has them stopped. This is not very
+                        * likely, since the driver won't have gotten any
+                        * (or hardly any) new packets while we weren't
+                        * on the right channel, and even if it happens
+                        * it will at most lead to queueing up one more
+                        * packet per queue in mac80211 rather than on
+                        * the interface qdisc.
+                        */
                        netif_tx_wake_all_queues(sdata->dev);
+               }
 
                /* re-enable beaconing */
                if (enable_beaconing &&
index d287fde0431d6b2e688da5400d0ef9f41d9cf1c2..ce671dfd238c115281608e9fdb96b3ac3ce433fd 100644 (file)
@@ -12,7 +12,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
-       ieee80211_scan_cancel(local);
+       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
+               ieee80211_scan_cancel(local);
 
        ieee80211_stop_queues_by_reason(hw,
                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
index be04d46110fe8cdccc5e07eb810b67ee39c5c20f..4f772de2f21327f0e6a3c78736898caff548abaa 100644 (file)
@@ -368,8 +368,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 
        ref = rate_control_alloc(name, local);
        if (!ref) {
-               printk(KERN_WARNING "%s: Failed to select rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               wiphy_warn(local->hw.wiphy,
+                          "Failed to select rate control algorithm\n");
                return -ENOENT;
        }
 
@@ -380,9 +380,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
                sta_info_flush(local, NULL);
        }
 
-       printk(KERN_DEBUG "%s: Selected rate control "
-              "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
-              ref->ops->name);
+       wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n",
+                   ref->ops->name);
 
        return 0;
 }
index aa41e382bbb3c67f55474cb2fe53f5b3f90d667b..ac205a33690f90f8058cdd98e0ea5982657bcb18 100644 (file)
@@ -605,10 +605,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
                        if (net_ratelimit())
-                               printk(KERN_DEBUG "%s: release an RX reorder "
-                                      "frame due to timeout on earlier "
-                                      "frames\n",
-                                      wiphy_name(hw->wiphy));
+                               wiphy_debug(hw->wiphy,
+                                           "release an RX reorder frame due to timeout on earlier frames\n");
 #endif
                        ieee80211_release_reorder_frame(hw, tid_agg_rx,
                                                        j, frames);
@@ -1002,6 +1000,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        case WLAN_CIPHER_SUITE_AES_CMAC:
                result = ieee80211_crypto_aes_cmac_decrypt(rx);
                break;
+       default:
+               /*
+                * We can reach here only with HW-only algorithms
+                * but why didn't it decrypt the frame?!
+                */
+               return RX_DROP_UNUSABLE;
        }
 
        /* either the frame has been decrypted or will be dropped */
@@ -1523,7 +1527,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * Allow EAPOL frames to us/the PAE group address regardless
         * of whether the frame was encrypted or not.
         */
-       if (ehdr->h_proto == htons(ETH_P_PAE) &&
+       if (ehdr->h_proto == rx->sdata->control_port_protocol &&
            (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
@@ -2481,6 +2485,11 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
 {
        struct sk_buff_head frames;
        struct ieee80211_rx_data rx = { };
+       struct tid_ampdu_rx *tid_agg_rx;
+
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+               return;
 
        __skb_queue_head_init(&frames);
 
@@ -2495,10 +2504,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                     test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
                rx.flags |= IEEE80211_RX_IN_SCAN;
 
-       spin_lock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);
-       ieee80211_sta_reorder_release(&sta->local->hw,
-               sta->ampdu_mlme.tid_rx[tid], &frames);
-       spin_unlock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);
+       spin_lock(&tid_agg_rx->reorder_lock);
+       ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
+       spin_unlock(&tid_agg_rx->reorder_lock);
 
        ieee80211_rx_handlers(&rx, &frames);
 }
@@ -2698,10 +2706,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                        skb_new = skb_copy(skb, GFP_ATOMIC);
                        if (!skb_new) {
                                if (net_ratelimit())
-                                       printk(KERN_DEBUG "%s: failed to copy "
-                                              "multicast frame for %s\n",
-                                              wiphy_name(local->hw.wiphy),
-                                              prev->name);
+                                       wiphy_debug(local->hw.wiphy,
+                                                   "failed to copy multicast frame for %s\n",
+                                                   prev->name);
                                goto next;
                        }
                        ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
index 31f233f7f51af0cecae3b59d49eff090efb0fe8c..d60389ba9b952c9cc60782151e24dc9860644235 100644 (file)
@@ -248,13 +248,11 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        return true;
 }
 
-void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        bool was_hw_scan;
 
-       trace_api_scan_completed(local, aborted);
-
        mutex_lock(&local->mtx);
 
        /*
@@ -312,6 +310,18 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        ieee80211_mesh_notify_scan_completed(local);
        ieee80211_queue_work(&local->hw, &local->work_work);
 }
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       trace_api_scan_completed(local, aborted);
+
+       set_bit(SCAN_COMPLETED, &local->scanning);
+       if (aborted)
+               set_bit(SCAN_ABORTED, &local->scanning);
+       ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+}
 EXPORT_SYMBOL(ieee80211_scan_completed);
 
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
@@ -449,7 +459,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 
        /* 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);
+               __ieee80211_scan_completed(&local->hw, false);
                return 1;
        }
 
@@ -641,6 +651,14 @@ void ieee80211_scan_work(struct work_struct *work)
        struct ieee80211_sub_if_data *sdata = local->scan_sdata;
        unsigned long next_delay = 0;
 
+       if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
+               bool aborted;
+
+               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);
@@ -651,7 +669,7 @@ void ieee80211_scan_work(struct work_struct *work)
                int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
                mutex_unlock(&local->mtx);
                if (rc)
-                       ieee80211_scan_completed(&local->hw, true);
+                       __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
@@ -666,7 +684,7 @@ void ieee80211_scan_work(struct work_struct *work)
                mutex_unlock(&local->mtx);
 
                if (rc)
-                       ieee80211_scan_completed(&local->hw, true);
+                       __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
@@ -676,7 +694,7 @@ void ieee80211_scan_work(struct work_struct *work)
         * Avoid re-scheduling when the sdata is going away.
         */
        if (!ieee80211_sdata_running(sdata)) {
-               ieee80211_scan_completed(&local->hw, true);
+               __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
@@ -783,5 +801,5 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
        mutex_unlock(&local->mtx);
 
        if (abortscan)
-               ieee80211_scan_completed(&local->hw, true);
+               __ieee80211_scan_completed(&local->hw, true);
 }
index 6d86f0c1ad0415acc4d96d0131d27bb2dc77f614..687077e49dc6ecaa44648db98a25138a12c14fd2 100644 (file)
@@ -174,8 +174,7 @@ static void __sta_info_free(struct ieee80211_local *local,
        }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
        kfree(sta);
@@ -262,8 +261,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Allocated STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_MESH
@@ -300,8 +298,9 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
                sta->uploaded = true;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (async)
-                       printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n",
-                              wiphy_name(local->hw.wiphy), sta->sta.addr);
+                       wiphy_debug(local->hw.wiphy,
+                                   "Finished adding IBSS STA %pM\n",
+                                   sta->sta.addr);
 #endif
        }
 
@@ -411,8 +410,8 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
                spin_unlock_irqrestore(&local->sta_lock, flags);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: Added IBSS STA %pM\n",
-                      wiphy_name(local->hw.wiphy), sta->sta.addr);
+               wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
+                           sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
                ieee80211_queue_work(&local->hw, &local->sta_finish_work);
@@ -459,8 +458,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
        }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Inserted STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
        /* move reference to rcu-protected */
@@ -690,8 +688,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 #endif
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Removed STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
        cancel_work_sync(&sta->drv_unblock_wk);
 
index 67a35841bef04aa13bdb33bb5b29fb4b42836a66..571b32bfc54c9b14321f6883404e3062d789750a 100644 (file)
@@ -114,11 +114,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
-               printk(KERN_DEBUG "%s: dropped TX filtered frame, "
-                      "queue_len=%d PS=%d @%lu\n",
-                      wiphy_name(local->hw.wiphy),
-                      skb_queue_len(&sta->tx_filtered),
-                      !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+               wiphy_debug(local->hw.wiphy,
+                           "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
+                           skb_queue_len(&sta->tx_filtered),
+                           !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
 #endif
        dev_kfree_skb(skb);
 }
index bc4fefc916634bbfbfb65b18edf886e28e222509..ccf373788ce9929dc2599034f4db310d1f9ed324 100644 (file)
@@ -351,8 +351,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 
        local->total_ps_buffered = total;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
-              wiphy_name(local->hw.wiphy), purged);
+       wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
+                   purged);
 #endif
 }
 
@@ -508,6 +508,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
                return ieee80211_tx_h_multicast_ps_buf(tx);
 }
 
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
+                    tx->sdata->control_port_no_encrypt))
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+       return TX_CONTINUE;
+}
+
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 {
@@ -527,7 +539,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
-                (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
+                (tx->skb->protocol != tx->sdata->control_port_protocol) &&
                 !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
                 (!ieee80211_is_robust_mgmt_frame(hdr) ||
                  (ieee80211_is_action(hdr->frame_control) &&
@@ -947,6 +959,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
        if (!tx->key)
                return TX_CONTINUE;
 
@@ -960,10 +974,16 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
                return ieee80211_crypto_ccmp_encrypt(tx);
        case WLAN_CIPHER_SUITE_AES_CMAC:
                return ieee80211_crypto_aes_cmac_encrypt(tx);
+       default:
+               /* handle hw-only algorithm */
+               if (info->control.hw_key) {
+                       ieee80211_tx_set_protected(tx);
+                       return TX_CONTINUE;
+               }
+               break;
+
        }
 
-       /* not reached */
-       WARN_ON(1);
        return TX_DROP;
 }
 
@@ -1341,6 +1361,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        CALL_TXH(ieee80211_tx_h_dynamic_ps);
        CALL_TXH(ieee80211_tx_h_check_assoc);
        CALL_TXH(ieee80211_tx_h_ps_buf);
+       CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
        CALL_TXH(ieee80211_tx_h_select_key);
        if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
                CALL_TXH(ieee80211_tx_h_rate_ctrl);
@@ -1513,8 +1534,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
                I802_DEBUG_INC(local->tx_expand_skb_head);
 
        if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
-               printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
-                      wiphy_name(local->hw.wiphy));
+               wiphy_debug(local->hw.wiphy,
+                           "failed to reallocate TX buffer\n");
                return -ENOMEM;
        }
 
@@ -1701,7 +1722,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        u16 ethertype, hdrlen,  meshhdrlen = 0;
        __le16 fc;
        struct ieee80211_hdr hdr;
-       struct ieee80211s_hdr mesh_hdr;
+       struct ieee80211s_hdr mesh_hdr __maybe_unused;
        const u8 *encaps_data;
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
@@ -1818,7 +1839,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 #endif
        case NL80211_IFTYPE_STATION:
                memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-               if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
+               if (sdata->u.mgd.use_4addr &&
+                   cpu_to_be16(ethertype) != sdata->control_port_protocol) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
@@ -1871,7 +1893,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (!ieee80211_vif_is_mesh(&sdata->vif) &&
                unlikely(!is_multicast_ether_addr(hdr.addr1) &&
                      !(sta_flags & WLAN_STA_AUTHORIZED) &&
-                     !(ethertype == ETH_P_PAE &&
+                     !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
                       compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -2070,8 +2092,7 @@ void ieee80211_tx_pending(unsigned long data)
 
                if (skb_queue_empty(&local->pending[i]))
                        list_for_each_entry_rcu(sdata, &local->interfaces, list)
-                               netif_tx_wake_queue(
-                                       netdev_get_tx_queue(sdata->dev, i));
+                               netif_wake_subqueue(sdata->dev, i);
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
index cd2b485fed4fe5b8d9002010c0d5cf1e99cb9d29..bd40b11d5ab9e514d7e75f887baebf65352e0370 100644 (file)
@@ -283,8 +283,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
 
        if (skb_queue_empty(&local->pending[queue])) {
                rcu_read_lock();
-               list_for_each_entry_rcu(sdata, &local->interfaces, list)
-                       netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
+               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+                               continue;
+                       netif_wake_subqueue(sdata->dev, queue);
+               }
                rcu_read_unlock();
        } else
                tasklet_schedule(&local->tx_pending_tasklet);
@@ -323,7 +326,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
+               netif_stop_subqueue(sdata->dev, queue);
        rcu_read_unlock();
 }
 
@@ -1308,7 +1311,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
         */
 
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        goto set;
index 927ffbd2aebcbaa1df4b224e2117c7e7fa6db1df..85a23de7bff346204c456519ca6a8692bfac7eb9 100644 (file)
@@ -136,6 +136,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                .len = sizeof(struct nl80211_sta_flag_update),
        },
        [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
+       [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
        [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
        [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
@@ -474,6 +476,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
                   dev->wiphy.max_num_pmkids);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
+
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
                goto nla_put_failure;
@@ -636,6 +641,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                        nla_nest_end(msg, nl_ftypes);
                }
 
+               nla_nest_end(msg, nl_ifs);
+
                nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
                if (!nl_ifs)
                        goto nla_put_failure;
@@ -3689,7 +3696,8 @@ unlock_rtnl:
        return err;
 }
 
-static int nl80211_crypto_settings(struct genl_info *info,
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+                                  struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
                                   int cipher_limit)
 {
@@ -3697,6 +3705,19 @@ static int nl80211_crypto_settings(struct genl_info *info,
 
        settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
 
+       if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
+               u16 proto;
+               proto = nla_get_u16(
+                       info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+               settings->control_port_ethertype = cpu_to_be16(proto);
+               if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+                   proto != ETH_P_PAE)
+                       return -EINVAL;
+               if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
+                       settings->control_port_no_encrypt = true;
+       } else
+               settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
+
        if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
                void *data;
                int len, i;
@@ -3824,7 +3845,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
                prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
-       err = nl80211_crypto_settings(info, &crypto, 1);
+       err = nl80211_crypto_settings(rdev, info, &crypto, 1);
        if (!err)
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                          ssid, ssid_len, ie, ie_len, use_mfp,
@@ -4301,7 +4322,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
 
-       err = nl80211_crypto_settings(info, &connect.crypto,
+       err = nl80211_crypto_settings(rdev, info, &connect.crypto,
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
                return err;
index 8d961cc4ae98f333002a12f121613802b03d95de..bca32eb8f446a90161c314e55042627953e84328 100644 (file)
@@ -183,7 +183,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                        return -EINVAL;
                break;
        default:
-               return -EINVAL;
+               /*
+                * We don't know anything about this algorithm,
+                * allow using it -- but the driver must check
+                * all parameters! We still check below whether
+                * or not the driver supports this algorithm,
+                * of course.
+                */
+               break;
        }
 
        if (params->seq) {
index 0ef17bc42bac05996eab6e2dada02fc67953c3dc..40385936e2861b86b8ec2dabea6ea76c4468d254 100644 (file)
@@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev)
 #endif
 
 #ifdef CONFIG_CFG80211_WEXT
-       if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
+       if (dev->ieee80211_ptr &&
            dev->ieee80211_ptr->wiphy &&
            dev->ieee80211_ptr->wiphy->wext &&
            dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
index 9818198add8a21444ba9183bbb8e4fc2c2199491..6fffe62d7c25b27cc9c6d6bc58635aa91f333e9f 100644 (file)
@@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
        wdev->wext.connect.ssid_len = len;
 
        wdev->wext.connect.crypto.control_port = false;
+       wdev->wext.connect.crypto.control_port_ethertype =
+                                       cpu_to_be16(ETH_P_PAE);
 
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out: