Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-agn-rxon.c
index 2a4ff83..dfdbea6 100644 (file)
@@ -316,10 +316,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames.
         *
-        * FIXME: which RXON requires a tune? Can we optimise this out in
-        *        some cases?
+        * It's expected we set power here if channel is changing.
         */
-       ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+       ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
        if (ret) {
                IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
                return ret;
@@ -472,6 +471,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
        struct iwl_rxon_context *tmp;
        struct ieee80211_sta *sta;
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       struct ieee80211_sta_ht_cap *ht_cap;
        bool need_multiple;
 
        lockdep_assert_held(&priv->mutex);
@@ -480,23 +480,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
        case NL80211_IFTYPE_STATION:
                rcu_read_lock();
                sta = ieee80211_find_sta(vif, bss_conf->bssid);
-               if (sta) {
-                       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-                       int maxstreams;
-
-                       maxstreams = (ht_cap->mcs.tx_params &
-                                     IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
-                                       >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
-                       maxstreams += 1;
-
-                       need_multiple = true;
-
-                       if ((ht_cap->mcs.rx_mask[1] == 0) &&
-                           (ht_cap->mcs.rx_mask[2] == 0))
-                               need_multiple = false;
-                       if (maxstreams <= 1)
-                               need_multiple = false;
-               } else {
+               if (!sta) {
                        /*
                         * If at all, this can only happen through a race
                         * when the AP disconnects us while we're still
@@ -504,7 +488,46 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
                         * will soon tell us about that.
                         */
                        need_multiple = false;
+                       rcu_read_unlock();
+                       break;
+               }
+
+               ht_cap = &sta->ht_cap;
+
+               need_multiple = true;
+
+               /*
+                * If the peer advertises no support for receiving 2 and 3
+                * stream MCS rates, it can't be transmitting them either.
+                */
+               if (ht_cap->mcs.rx_mask[1] == 0 &&
+                   ht_cap->mcs.rx_mask[2] == 0) {
+                       need_multiple = false;
+               } else if (!(ht_cap->mcs.tx_params &
+                                               IEEE80211_HT_MCS_TX_DEFINED)) {
+                       /* If it can't TX MCS at all ... */
+                       need_multiple = false;
+               } else if (ht_cap->mcs.tx_params &
+                                               IEEE80211_HT_MCS_TX_RX_DIFF) {
+                       int maxstreams;
+
+                       /*
+                        * But if it can receive them, it might still not
+                        * be able to transmit them, which is what we need
+                        * to check here -- so check the number of streams
+                        * it advertises for TX (if different from RX).
+                        */
+
+                       maxstreams = (ht_cap->mcs.tx_params &
+                                IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
+                       maxstreams >>=
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+                       maxstreams += 1;
+
+                       if (maxstreams <= 1)
+                               need_multiple = false;
                }
+
                rcu_read_unlock();
                break;
        case NL80211_IFTYPE_ADHOC: