mac80211: let drivers wake but not start queues
[deliverable/linux.git] / net / mac80211 / main.c
index f277407f0f5a848d3484036f5e4a992d84903b20..9761d9bd5a79338006600a2a43863a53155da8a6 100644 (file)
@@ -35,8 +35,6 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
-#define SUPP_MCS_SET_LEN 16
-
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -112,7 +110,13 @@ static int ieee80211_master_open(struct net_device *dev)
                        break;
                }
        }
-       return res;
+
+       if (res)
+               return res;
+
+       netif_start_queue(local->mdev);
+
+       return 0;
 }
 
 static int ieee80211_master_stop(struct net_device *dev)
@@ -1068,56 +1072,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
        struct ieee80211_supported_band *sband;
        struct ieee80211_ht_info ht_conf;
        struct ieee80211_ht_bss_info ht_bss_conf;
-       int i;
        u32 changed = 0;
+       int i;
+       u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+       u8 tx_mcs_set_cap;
 
        sband = local->hw.wiphy->bands[conf->channel->band];
 
+       memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+       memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+
        /* HT is not supported */
        if (!sband->ht_info.ht_supported) {
                conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-               return 0;
+               goto out;
        }
 
-       memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
-       memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
-       if (enable_ht) {
-               if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+       /* disable HT */
+       if (!enable_ht) {
+               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
                        changed |= BSS_CHANGED_HT;
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+               conf->ht_conf.ht_supported = 0;
+               goto out;
+       }
 
-               conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
-               ht_conf.ht_supported = 1;
 
-               ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
-               ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
-               ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+               changed |= BSS_CHANGED_HT;
 
-               for (i = 0; i < SUPP_MCS_SET_LEN; i++)
-                       ht_conf.supp_mcs_set[i] =
-                                       sband->ht_info.supp_mcs_set[i] &
-                                       req_ht_cap->supp_mcs_set[i];
+       conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+       ht_conf.ht_supported = 1;
 
-               ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
-               ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
-               ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+       ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+       ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+       ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+       ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+       ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+       ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
 
-               ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
-               ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+       ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+       ht_conf.ampdu_density = req_ht_cap->ampdu_density;
 
-               /* if bss configuration changed store the new one */
-               if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
-                   memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
-                       changed |= BSS_CHANGED_HT;
-                       memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
-                       memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
-               }
-       } else {
-               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
-                       changed |= BSS_CHANGED_HT;
-               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-       }
+       /* Bits 96-100 */
+       tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+       /* configure suppoerted Tx MCS according to requested MCS
+        * (based in most cases on Rx capabilities of peer) and self
+        * Tx MCS capabilities (as defined by low level driver HW
+        * Tx capabilities) */
+       if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+               goto check_changed;
+
+       /* Counting from 0 therfore + 1 */
+       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+               max_tx_streams = ((tx_mcs_set_cap &
+                               IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
 
+       for (i = 0; i < max_tx_streams; i++)
+               ht_conf.supp_mcs_set[i] =
+                       sband->ht_info.supp_mcs_set[i] &
+                                       req_ht_cap->supp_mcs_set[i];
+
+       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+               for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+                    i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+                       ht_conf.supp_mcs_set[i] =
+                               sband->ht_info.supp_mcs_set[i] &
+                                       req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+       /* if bss configuration changed store the new one */
+       if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+           memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+               changed |= BSS_CHANGED_HT;
+               memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+               memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+       }
+out:
        return changed;
 }
 
@@ -1702,13 +1734,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        local->hw.conf.beacon_int = 1000;
 
-       local->wstats_flags |= local->hw.max_rssi ?
-                              IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
-       local->wstats_flags |= local->hw.max_signal ?
+       local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+                                                 IEEE80211_HW_SIGNAL_DB |
+                                                 IEEE80211_HW_SIGNAL_DBM) ?
                               IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
-       local->wstats_flags |= local->hw.max_noise ?
+       local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
                               IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
-       if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->wstats_flags |= IW_QUAL_DBM;
 
        result = sta_info_start(local);
@@ -1772,6 +1804,7 @@ fail_wep:
 fail_rate:
        ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
        unregister_netdevice(local->mdev);
+       local->mdev = NULL;
 fail_dev:
        rtnl_unlock();
        sta_info_stop(local);
@@ -1779,8 +1812,10 @@ fail_sta_info:
        debugfs_hw_del(local);
        destroy_workqueue(local->hw.workqueue);
 fail_workqueue:
-       ieee80211_if_free(local->mdev);
-       local->mdev = NULL;
+       if (local->mdev != NULL) {
+               ieee80211_if_free(local->mdev);
+               local->mdev = NULL;
+       }
 fail_mdev_alloc:
        wiphy_unregister(local->hw.wiphy);
        return result;
This page took 0.029702 seconds and 5 git commands to generate.